import Foundation
import HealthKit
import SwiftData
import UIKit
import os.log

private let logger = Logger(subsystem: "ro.xdev.healthprobe", category: "HealthKitService")

enum TypeCategory: String, CaseIterable {
    case activity    = "Activity"
    case heart       = "Heart"
    case mobility    = "Mobility"
    case respiratory = "Respiratory"
    case sleep       = "Sleep"
    case hearing     = "Hearing"
    case body        = "Body"
    case nutrition   = "Nutrition"
    case reproductive = "Reproductive Health"
    case symptoms    = "Symptoms"
    case other       = "Other"
}

struct MonitoredType: Identifiable, @unchecked Sendable {
    let id: String
    let displayName: String
    let category: TypeCategory
    let isEnabledByDefault: Bool
    let objectType: HKObjectType?   // nil = unsupported on this OS/device
}

extension Array where Element == MonitoredType {
    func sortedByFetchDisplayNameDescending() -> [MonitoredType] {
        sorted {
            let displayNameOrder = $0.displayName.localizedCaseInsensitiveCompare($1.displayName)
            if displayNameOrder == .orderedSame {
                return $0.id > $1.id
            }
            return displayNameOrder == .orderedDescending
        }
    }
}

enum LegacySwiftDataBridgeError: LocalizedError {
    case notConfigured
    case snapshotNotSaved

    var errorDescription: String? {
        switch self {
        case .notConfigured:
            return "Legacy SwiftData bridge is not configured."
        case .snapshotNotSaved:
            return "Snapshot was not saved to database. This may indicate a HealthKit permission issue or data corruption. Try requesting health access again in the Actions section."
        }
    }
}

struct AmbiguousDisappearedMetric: Identifiable, Equatable, Sendable {
    let id: String
    let displayName: String
    let previousCount: Int
}

struct LegacySnapshotTypeSummary: Sendable {
    let typeIdentifier: String
    let displayName: String
    let count: Int
    let quality: SnapshotQuality
}

struct LegacySnapshotOutcome: Sendable {
    let snapshotID: UUID
    let timestamp: Date
    let deviceID: String
    let triggerReason: String
    let retryOfSnapshotID: UUID?
    let previousSnapshotID: UUID?
    let isChainStart: Bool
    let snapshotChecksum: String
    let monitoredTypeSetHash: String
    let monitoredRegistryVersion: Int
}

struct LegacySnapshotCaptureResult: Sendable {
    let outcome: LegacySnapshotOutcome
    let snapshotQuality: SnapshotQuality
    let typeSummaries: [LegacySnapshotTypeSummary]
    let shouldAutoSaveKnownUnauthorizedPartial: Bool
    let ambiguousDisappearedMetrics: [AmbiguousDisappearedMetric]
}

enum LegacySwiftDataBridge {
    private static var container: ModelContainer?
    private static var context: ModelContext?
    private static var pendingSnapshots: [UUID: HealthSnapshot] = [:]

    static func configure(container: ModelContainer) {
        self.container = container
        context = ModelContext(container)
    }

    static func createSnapshot(
        using healthKit: HealthKitService,
        selectedTypeIDs: Set<String>,
        adaptiveTimeoutsEnabled: Bool,
        triggerReason: String,
        retryOfSnapshotID: UUID?,
        timeoutMultiplier: Double,
        reviewAmbiguousCompleteDisappearedTypes: Bool,
        progress: SnapshotFetchProgress?
    ) async throws -> LegacySnapshotCaptureResult {
        let snapshot = try await healthKit.createSnapshot(
            in: modelContext(),
            selectedTypeIDs: selectedTypeIDs,
            adaptiveTimeoutsEnabled: adaptiveTimeoutsEnabled,
            triggerReason: triggerReason,
            retryOfSnapshotID: retryOfSnapshotID,
            timeoutMultiplier: timeoutMultiplier,
            reviewAmbiguousCompleteDisappearedTypes: reviewAmbiguousCompleteDisappearedTypes,
            progress: progress
        )

        let ambiguousDisappearedMetrics = snapshot.snapshotQuality == .complete
            ? ambiguousDisappearedMetrics(for: snapshot)
            : []

        let shouldKeepPending = snapshot.snapshotQuality != .complete || !ambiguousDisappearedMetrics.isEmpty
        if shouldKeepPending {
            pendingSnapshots[snapshot.id] = snapshot
        } else if try !snapshotExists(id: snapshot.id) {
            throw LegacySwiftDataBridgeError.snapshotNotSaved
        }

        return LegacySnapshotCaptureResult(
            outcome: snapshotOutcome(from: snapshot),
            snapshotQuality: snapshot.snapshotQuality,
            typeSummaries: typeSummaries(from: snapshot),
            shouldAutoSaveKnownUnauthorizedPartial: shouldAutoSaveKnownUnauthorizedPartial(snapshot: snapshot),
            ambiguousDisappearedMetrics: ambiguousDisappearedMetrics
        )
    }

    static func savePartialSnapshot(
        id snapshotID: UUID,
        using healthKit: HealthKitService
    ) async throws -> LegacySnapshotOutcome {
        guard let snapshot = try resolveSnapshot(id: snapshotID) else {
            throw LegacySwiftDataBridgeError.snapshotNotSaved
        }
        let saved = try await healthKit.savePartialSnapshot(snapshot, in: modelContext())
        pendingSnapshots.removeValue(forKey: snapshotID)
        return snapshotOutcome(from: saved)
    }

    static func saveReviewedCompleteSnapshot(
        id snapshotID: UUID,
        using healthKit: HealthKitService
    ) async throws -> LegacySnapshotOutcome {
        guard let snapshot = try resolveSnapshot(id: snapshotID) else {
            throw LegacySwiftDataBridgeError.snapshotNotSaved
        }
        let saved = try await healthKit.saveReviewedCompleteSnapshot(snapshot, in: modelContext())
        pendingSnapshots.removeValue(forKey: snapshotID)
        return snapshotOutcome(from: saved)
    }

    static func markMetricsUnauthorized(
        snapshotID: UUID,
        typeIdentifiers: Set<String>,
        using healthKit: HealthKitService
    ) async throws -> LegacySnapshotOutcome {
        guard let snapshot = try resolveSnapshot(id: snapshotID) else {
            throw LegacySwiftDataBridgeError.snapshotNotSaved
        }

        for typeCount in snapshot.typeCounts ?? [] where typeIdentifiers.contains(typeCount.typeIdentifier) {
            typeCount.count = -1
            typeCount.contentHash = ""
            typeCount.earliestDate = nil
            typeCount.latestDate = nil
            typeCount.quality = .unauthorized
            typeCount.yearlyCounts = []
        }
        snapshot.snapshotQuality = healthKit.deriveSnapshotQuality(from: snapshot.typeCounts ?? [])

        let saved = try await healthKit.savePartialSnapshot(snapshot, in: modelContext())
        pendingSnapshots.removeValue(forKey: snapshotID)
        return snapshotOutcome(from: saved)
    }

    static func snapshotExists(id: UUID) throws -> Bool {
        var descriptor = FetchDescriptor<HealthSnapshot>(
            predicate: #Predicate<HealthSnapshot> { $0.id == id }
        )
        descriptor.fetchLimit = 1
        return try !modelContext().fetch(descriptor).isEmpty
    }

    static func previousSnapshot(for snapshot: HealthSnapshot) -> HealthSnapshot? {
        guard let previousID = snapshot.previousSnapshotID else { return nil }
        let descriptor = FetchDescriptor<HealthSnapshot>(
            predicate: #Predicate<HealthSnapshot> { $0.id == previousID }
        )
        return try? modelContext().fetch(descriptor).first
    }

    static func deleteSnapshot(id: UUID) throws {
        pendingSnapshots.removeValue(forKey: id)
        let context = try modelContext()
        var descriptor = FetchDescriptor<HealthSnapshot>(
            predicate: #Predicate<HealthSnapshot> { $0.id == id }
        )
        descriptor.fetchLimit = 1
        if let snapshot = try context.fetch(descriptor).first {
            context.delete(snapshot)
        }
    }

    static func discardPendingSnapshot(id: UUID) {
        pendingSnapshots.removeValue(forKey: id)
    }

    private static func fetchSnapshot(id: UUID) throws -> HealthSnapshot? {
        let context = try modelContext()
        var descriptor = FetchDescriptor<HealthSnapshot>(
            predicate: #Predicate<HealthSnapshot> { $0.id == id }
        )
        descriptor.fetchLimit = 1
        return try context.fetch(descriptor).first
    }

    private static func resolveSnapshot(id: UUID) throws -> HealthSnapshot? {
        if let pending = pendingSnapshots[id] {
            return pending
        }
        return try fetchSnapshot(id: id)
    }

    private static func ambiguousDisappearedMetrics(for snapshot: HealthSnapshot) -> [AmbiguousDisappearedMetric] {
        guard let previous = previousSnapshot(for: snapshot) else { return [] }
        let previousByType = Dictionary(
            uniqueKeysWithValues: (previous.typeCounts ?? []).map { ($0.typeIdentifier, $0) }
        )

        return (snapshot.typeCounts ?? []).compactMap { current in
            guard current.quality == .complete,
                  current.count == 0,
                  let previous = previousByType[current.typeIdentifier],
                  previous.quality == .complete,
                  previous.count > 0 else {
                return nil
            }
            return AmbiguousDisappearedMetric(
                id: current.typeIdentifier,
                displayName: current.displayName,
                previousCount: previous.count
            )
        }.sorted { $0.displayName < $1.displayName }
    }

    private static func shouldAutoSaveKnownUnauthorizedPartial(snapshot: HealthSnapshot) -> Bool {
        let currentUnauthorized = (snapshot.typeCounts ?? []).filter { $0.quality == .unauthorized }
        guard snapshot.snapshotQuality != .complete,
              !currentUnauthorized.isEmpty,
              !(snapshot.typeCounts ?? []).contains(where: { $0.quality == .failed }),
              let previous = previousSnapshot(for: snapshot) else {
            return false
        }

        let previousByType = Dictionary(
            uniqueKeysWithValues: (previous.typeCounts ?? []).map { ($0.typeIdentifier, $0) }
        )

        return currentUnauthorized.allSatisfy { previousByType[$0.typeIdentifier]?.quality == .unauthorized }
    }

    private static func typeSummaries(from snapshot: HealthSnapshot) -> [LegacySnapshotTypeSummary] {
        (snapshot.typeCounts ?? []).map { typeCount in
            LegacySnapshotTypeSummary(
                typeIdentifier: typeCount.typeIdentifier,
                displayName: typeCount.displayName,
                count: typeCount.count,
                quality: typeCount.quality
            )
        }
    }

    private static func snapshotOutcome(from snapshot: HealthSnapshot) -> LegacySnapshotOutcome {
        LegacySnapshotOutcome(
            snapshotID: snapshot.id,
            timestamp: snapshot.timestamp,
            deviceID: snapshot.deviceID,
            triggerReason: snapshot.triggerReason,
            retryOfSnapshotID: snapshot.retryOfSnapshotID,
            previousSnapshotID: snapshot.previousSnapshotID,
            isChainStart: snapshot.isChainStart,
            snapshotChecksum: HashService.snapshotChecksum(typeCounts: snapshot.typeCounts ?? []),
            monitoredTypeSetHash: snapshot.monitoredTypeSetHash,
            monitoredRegistryVersion: snapshot.monitoredRegistryVersion
        )
    }

    private static func modelContext() throws -> ModelContext {
        if let context { return context }
        guard let container else {
            throw LegacySwiftDataBridgeError.notConfigured
        }
        let context = ModelContext(container)
        self.context = context
        return context
    }
}

final class HealthKitService {
    static let shared = HealthKitService()
    let store = HKHealthStore()
    private let archiveStore: HealthArchiveStore

    private init(archiveStore: HealthArchiveStore = SQLiteHealthArchiveStore.shared) {
        self.archiveStore = archiveStore
    }

    static let allTypes: [MonitoredType] = buildAllTypes()

    static let defaultInitialTimeoutSeconds: TimeInterval = LocalMetricTimeoutProfile.defaultInitialTimeout
    static let maximumTimeoutSeconds: TimeInterval = LocalMetricTimeoutProfile.maximumTimeout
    static let captureOperationWatchdogTimeoutSeconds: TimeInterval = 12 * 60 * 60
    // Prevents 3N simultaneous HK queries from exhausting resources at N=20 types.
    static let maxConcurrentTypeFetches = 6

    var isAvailable: Bool { HKHealthStore.isHealthDataAvailable() }

    var hasRequestedPermissionsBefore: Bool {
        get {
            UserDefaults.standard.bool(forKey: "healthkit.permissions.requested")
        }
        set {
            UserDefaults.standard.set(newValue, forKey: "healthkit.permissions.requested")
        }
    }

    // MARK: - Authorization

    func requestAuthorization() async throws {
        guard isAvailable else { return }
        let readTypes = Set(Self.allTypes.compactMap { $0.objectType })
        try await store.requestAuthorization(toShare: [], read: readTypes)
        hasRequestedPermissionsBefore = true
    }

    // MARK: - Snapshot creation

    @MainActor
    func createSnapshot(
        in context: ModelContext,
        selectedTypeIDs: Set<String>,
        adaptiveTimeoutsEnabled: Bool,
        triggerReason: String = "manual",
        retryOfSnapshotID: UUID? = nil,
        timeoutMultiplier: Double = 1,
        reviewAmbiguousCompleteDisappearedTypes: Bool = false,
        progress: SnapshotFetchProgress? = nil
    ) async throws -> HealthSnapshot {
        let active = Self.allTypes
            .filter { selectedTypeIDs.contains($0.id) }
            .sortedByFetchDisplayNameDescending()
        let deviceResolution = KeychainService.resolveDeviceID(swiftDataStoreIsEmpty: isStoreEmpty(context: context))

        let snapshot = HealthSnapshot(
            timestamp: Date(),
            osVersion: ProcessInfo.processInfo.operatingSystemVersionString,
            deviceName: UIDevice.current.name,
            deviceID: deviceResolution.id
        )
        let intendedTypeIDs = active.map { $0.id }
        let monitoredTypeSetHash = HashService.typeSetHash(typeIDs: intendedTypeIDs)
        let archiveObservationID = try await archiveStore.beginObservation(
            observedAt: snapshot.timestamp,
            triggerReason: triggerReason,
            selectedTypeSetHash: monitoredTypeSetHash
        )
        snapshot.archiveObservationID = archiveObservationID
        snapshot.monitoredTypeSetHash = monitoredTypeSetHash
        snapshot.recoveredDeviceID = deviceResolution.isRecovered
        snapshot.triggerReason = triggerReason
        snapshot.retryOfSnapshotID = retryOfSnapshotID
        snapshot.yearlyCountTimezoneIdentifier = TimeZone.current.identifier
        let previousSnapshot = findPreviousSnapshot(deviceID: snapshot.deviceID, excluding: snapshot.id, context: context)
        // Fetch raw HealthKit data one type at a time, then assemble each SwiftData model
        // immediately so large per-type archives are not duplicated in an intermediate result array.
        let typeCounts = await fetchAllTypeCounts(
            for: active,
            context: context,
            snapshot: snapshot,
            previousSnapshot: previousSnapshot,
            archiveObservationID: archiveObservationID,
            adaptiveTimeoutsEnabled: adaptiveTimeoutsEnabled,
            timeoutMultiplier: timeoutMultiplier,
            progress: progress
        )
        snapshot.typeCounts = typeCounts

        applyStickyUnavailableState(
            snapshot: snapshot,
            typeCounts: typeCounts,
            context: context
        )

        // Invariant assertions before save — debug asserts + release silent correction
        for tc in typeCounts {
            let isComplete = tc.quality == SnapshotQuality.complete
            assert(
                !isComplete || tc.count >= 0,
                "TypeCount with quality .complete must have count >= 0"
            )
            assert(
                isComplete || tc.count == -1,
                "TypeCount with quality != .complete must have count == -1"
            )
            if !isComplete && tc.count != -1 {
                logger.critical("TypeCount invariant violation: quality=\(tc.quality.rawValue) count=\(tc.count) type=\(tc.typeIdentifier)")
                tc.count = -1
            }
        }

        snapshot.snapshotQuality = deriveSnapshotQuality(from: typeCounts)
        updateSnapshotSummaryCache(snapshot: snapshot, typeCounts: typeCounts)

        configureSnapshotMetadata(
            snapshot,
            typeCounts: typeCounts,
            intendedTypeIDs: intendedTypeIDs,
            context: context
        )
        markContentEquivalenceIfNeeded(
            snapshot: snapshot,
            typeCounts: typeCounts,
            context: context
        )
        precomputeTypeCountDetailCaches(
            snapshot: snapshot,
            typeCounts: typeCounts,
            context: context
        )

        if snapshot.snapshotQuality == .complete,
           reviewAmbiguousCompleteDisappearedTypes,
           hasAmbiguousCompleteDisappearance(snapshot: snapshot, typeCounts: typeCounts, context: context) {
            try await archiveStore.finishObservation(
                observationID: archiveObservationID,
                status: "needs_review",
                endedAt: Date()
            )
            return snapshot
        }

        do {
            if snapshot.snapshotQuality == .complete {
                try await persistSnapshot(snapshot, typeCounts: typeCounts, context: context)
            }
            try await archiveStore.finishObservation(
                observationID: archiveObservationID,
                status: snapshot.snapshotQuality == .complete ? "completed" : "partial_\(snapshot.snapshotQuality.rawValue)",
                endedAt: Date()
            )
        } catch {
            try? await archiveStore.finishObservation(
                observationID: archiveObservationID,
                status: "failed",
                endedAt: Date()
            )
            throw error
        }

        return snapshot
    }

    @MainActor
    func savePartialSnapshot(_ snapshot: HealthSnapshot, in context: ModelContext) async throws -> HealthSnapshot {
        let typeCounts = snapshot.typeCounts ?? []
        guard snapshot.snapshotQuality != .complete else {
            return snapshot
        }

        updateSnapshotSummaryCache(snapshot: snapshot, typeCounts: typeCounts)

        configureSnapshotMetadata(
            snapshot,
            typeCounts: typeCounts,
            intendedTypeIDs: typeCounts.map(\.typeIdentifier),
            context: context
        )
        markContentEquivalenceIfNeeded(
            snapshot: snapshot,
            typeCounts: typeCounts,
            context: context
        )
        precomputeTypeCountDetailCaches(
            snapshot: snapshot,
            typeCounts: typeCounts,
            context: context
        )
        try await persistSnapshot(snapshot, typeCounts: typeCounts, context: context)
        return snapshot
    }

    @MainActor
    func saveReviewedCompleteSnapshot(_ snapshot: HealthSnapshot, in context: ModelContext) async throws -> HealthSnapshot {
        let typeCounts = snapshot.typeCounts ?? []
        snapshot.snapshotQuality = deriveSnapshotQuality(from: typeCounts)
        guard snapshot.snapshotQuality == .complete else {
            return try await savePartialSnapshot(snapshot, in: context)
        }

        updateSnapshotSummaryCache(snapshot: snapshot, typeCounts: typeCounts)

        configureSnapshotMetadata(
            snapshot,
            typeCounts: typeCounts,
            intendedTypeIDs: typeCounts.map(\.typeIdentifier),
            context: context
        )
        markContentEquivalenceIfNeeded(
            snapshot: snapshot,
            typeCounts: typeCounts,
            context: context
        )
        precomputeTypeCountDetailCaches(
            snapshot: snapshot,
            typeCounts: typeCounts,
            context: context
        )
        try await persistSnapshot(snapshot, typeCounts: typeCounts, context: context)
        return snapshot
    }

    // MARK: - Snapshot persistence

    private func persistSnapshot(
        _ snapshot: HealthSnapshot,
        typeCounts: [TypeCount],
        context: ModelContext
    ) async throws {
        context.insert(snapshot)
        for typeCount in typeCounts {
            context.insert(typeCount)
            typeCount.snapshot = snapshot
        }
        snapshot.typeCounts = typeCounts

        try context.save()
    }

    private func updateSnapshotSummaryCache(
        snapshot: HealthSnapshot,
        typeCounts: [TypeCount]
    ) {
        snapshot.cachedSummaryVersion = HealthSnapshot.currentCachedSummaryVersion
        snapshot.cachedTypeCount = typeCounts.count
        snapshot.cachedRecordCount = typeCounts.reduce(0) { partial, typeCount in
            typeCount.count > 0 ? partial + typeCount.count : partial
        }

        let datedTypeCounts = typeCounts.filter { !$0.isUnsupported && $0.count > 0 }
        snapshot.cachedEarliestRecordDate = datedTypeCounts.compactMap(\.earliestDate).min()
        snapshot.cachedLatestRecordDate = datedTypeCounts.compactMap(\.latestDate).max()
    }

    private func configureSnapshotMetadata(
        _ snapshot: HealthSnapshot,
        typeCounts: [TypeCount],
        intendedTypeIDs: [String],
        context: ModelContext
    ) {
        // Chain metadata — set BEFORE context.save()
        // localSequenceNumber is used here solely to find the latest local candidate during
        // snapshot creation. Once previousSnapshotID is set, all chain reconstruction must use
        // previousSnapshotID exclusively — never reconstruct a chain by walking localSequenceNumber.
        let previous = findPreviousSnapshot(deviceID: snapshot.deviceID, excluding: snapshot.id, context: context)
        if let previous {
            snapshot.previousSnapshotID = previous.id
            snapshot.localSequenceNumber = previous.localSequenceNumber + 1
            snapshot.isChainStart = false

            snapshot.monitoredTypeSetHash = HashService.typeSetHash(typeIDs: intendedTypeIDs)
            if snapshot.monitoredTypeSetHash != previous.monitoredTypeSetHash {
                snapshot.monitoredRegistryVersion = previous.monitoredRegistryVersion + 1
            } else {
                snapshot.monitoredRegistryVersion = previous.monitoredRegistryVersion
            }

            // Auto-detect post-restore: previous was fully unauthorized, current is complete
            if previous.snapshotQuality == SnapshotQuality.unauthorized && snapshot.snapshotQuality == SnapshotQuality.complete {
                snapshot.isPostRestore = true
                snapshot.isPostRestoreInferred = true
            }
        } else {
            snapshot.previousSnapshotID = nil
            snapshot.localSequenceNumber = 0
            snapshot.isChainStart = true
            snapshot.monitoredTypeSetHash = HashService.typeSetHash(typeIDs: intendedTypeIDs)
            snapshot.monitoredRegistryVersion = 0

            // Auto-detect post-restore on chain start with significant data
            let completeTypeCounts = typeCounts.filter { $0.quality == SnapshotQuality.complete }
            let completeCount = completeTypeCounts.reduce(0) { $0 + max($1.count, 0) }
            if completeCount > 1000 {
                snapshot.isPostRestore = true
                snapshot.isPostRestoreInferred = true
            }
        }

        // Device metadata — informational only, never used for chain linkage
        snapshot.hardwareModel = hardwareModel()
        snapshot.appBuildVersion = appBuildVersion()
    }

    private func applyStickyUnavailableState(
        snapshot: HealthSnapshot,
        typeCounts: [TypeCount],
        context: ModelContext
    ) {
        guard let previous = findPreviousSnapshot(deviceID: snapshot.deviceID, excluding: snapshot.id, context: context) else {
            return
        }

        let previousByType = Dictionary(
            uniqueKeysWithValues: (previous.typeCounts ?? []).map { ($0.typeIdentifier, $0) }
        )

        for current in typeCounts {
            guard current.quality == .complete,
                  current.count == 0,
                  let previousType = previousByType[current.typeIdentifier],
                  previousType.quality == .unauthorized else {
                continue
            }

            current.count = -1
            current.contentHash = ""
            current.earliestDate = nil
            current.latestDate = nil
            current.quality = .unauthorized
            current.yearlyCounts = []
        }
    }

    private func precomputeTypeCountDetailCaches(
        snapshot: HealthSnapshot,
        typeCounts: [TypeCount],
        context _: ModelContext
    ) {
        MemoryLog.log("healthKit.precomputeDetailCaches.disabled", metadata: [
            "typeCountCount": "\(typeCounts.count)",
            "hasPrevious": "\(snapshot.previousSnapshotID != nil)",
            "reason": "legacySwiftDataCacheCrash"
        ])
    }

    private func markContentEquivalenceIfNeeded(
        snapshot: HealthSnapshot,
        typeCounts: [TypeCount],
        context: ModelContext
    ) {
        snapshot.contentEquivalentSnapshotID = nil
        for typeCount in typeCounts {
            typeCount.contentEquivalentTypeCountID = nil
        }

        guard let previousID = snapshot.previousSnapshotID,
              let previous = fetchSnapshot(id: previousID, context: context),
              previous.monitoredTypeSetHash == snapshot.monitoredTypeSetHash else {
            return
        }

        let previousByType = Dictionary(
            uniqueKeysWithValues: (previous.typeCounts ?? []).map { ($0.typeIdentifier, $0) }
        )

        for typeCount in typeCounts {
            guard let previousType = previousByType[typeCount.typeIdentifier],
                  areTypeCountsContentEquivalent(typeCount, previousType) else {
                continue
            }

            typeCount.contentEquivalentTypeCountID = previousType.contentRepresentativeTypeCountID
        }

        if areTypeCountsContentEquivalent(previous.typeCounts ?? [], typeCounts) {
            snapshot.contentEquivalentSnapshotID = previous.contentRepresentativeSnapshotID
        }
    }

    private func areTypeCountsContentEquivalent(_ lhs: [TypeCount], _ rhs: [TypeCount]) -> Bool {
        let lhsByType = Dictionary(uniqueKeysWithValues: lhs.map { ($0.typeIdentifier, $0) })
        let rhsByType = Dictionary(uniqueKeysWithValues: rhs.map { ($0.typeIdentifier, $0) })
        guard lhsByType.keys == rhsByType.keys else { return false }

        for typeIdentifier in lhsByType.keys {
            guard let lhsType = lhsByType[typeIdentifier],
                  let rhsType = rhsByType[typeIdentifier],
                  lhsType.count == rhsType.count,
                  lhsType.contentHash == rhsType.contentHash,
                  lhsType.quality == rhsType.quality,
                  lhsType.isUnsupported == rhsType.isUnsupported else {
                return false
            }
        }

        return true
    }

    private func areTypeCountsContentEquivalent(_ lhs: TypeCount, _ rhs: TypeCount) -> Bool {
        lhs.count == rhs.count &&
        lhs.contentHash == rhs.contentHash &&
        lhs.quality == rhs.quality &&
        lhs.isUnsupported == rhs.isUnsupported
    }

    private func hasAmbiguousCompleteDisappearance(
        snapshot: HealthSnapshot,
        typeCounts: [TypeCount],
        context: ModelContext
    ) -> Bool {
        guard let previousID = snapshot.previousSnapshotID,
              let previous = fetchSnapshot(id: previousID, context: context) else {
            return false
        }

        let previousByType = Dictionary(
            uniqueKeysWithValues: (previous.typeCounts ?? []).map { ($0.typeIdentifier, $0) }
        )

        return typeCounts.contains { current in
            guard current.quality == .complete,
                  current.count == 0,
                  let previous = previousByType[current.typeIdentifier],
                  previous.quality == .complete,
                  previous.count > 0 else {
                return false
            }
            return true
        }
    }

    // MARK: - Per-type fetch pipeline

    // Fetches sequentially to prevent race conditions and resource exhaustion.
    @MainActor
    private func fetchAllTypeCounts(
        for active: [MonitoredType],
        context: ModelContext,
        snapshot: HealthSnapshot,
        previousSnapshot: HealthSnapshot?,
        archiveObservationID: Int64,
        adaptiveTimeoutsEnabled: Bool,
        timeoutMultiplier: Double,
        progress: SnapshotFetchProgress? = nil
    ) async -> [TypeCount] {
        var typeCounts: [TypeCount] = []
        typeCounts.reserveCapacity(active.count)

        for monitoredType in active {
            var profile = timeoutProfile(for: monitoredType)
            let timeout = timeoutForFetch(
                profile: profile,
                adaptiveTimeoutsEnabled: adaptiveTimeoutsEnabled,
                timeoutMultiplier: timeoutMultiplier
            )
            var result = await fetchTypeCountData(
                for: monitoredType,
                timeoutProfile: profile,
                timeoutSeconds: timeout,
                previousTypeCount: previousSnapshot?.typeCounts?.first { $0.typeIdentifier == monitoredType.id },
                archiveObservationID: archiveObservationID,
                progress: progress
            )
            updateTimeoutProfile(&profile, with: result, monitoredType: monitoredType)
            LocalMetricTimeoutProfileStore.save(profile)
            result.applyTimeoutProfile(profile)
            progress?.updateTimeoutProfile(from: profile, for: monitoredType.id)
            let typeCount = result.makeTypeCount()
            typeCount.snapshot = snapshot
            typeCounts.append(typeCount)
        }
        return typeCounts
    }

    private func fetchTypeCountData(
        for monitoredType: MonitoredType,
        timeoutProfile: LocalMetricTimeoutProfile,
        timeoutSeconds: TimeInterval,
        previousTypeCount: TypeCount?,
        archiveObservationID: Int64,
        progress: SnapshotFetchProgress? = nil
    ) async -> TypeCountFetchResult {
        let started = Date()
        progress?.updateStatus(monitoredType.id, status: .fetching)

        // Unsupported type: HKObjectType factory returned nil for this identifier
        guard let objectType = monitoredType.objectType,
              let sampleType = objectType as? HKSampleType else {
            var result = TypeCountFetchResult(
                typeIdentifier: monitoredType.id,
                displayName: monitoredType.displayName,
                count: -1,
                contentHash: "",
                earliestDate: nil,
                latestDate: nil,
                quality: SnapshotQuality.failed,
                diagnosticQuality: HealthKitAPICallResult.Status.unsupported.rawValue,
                isUnsupported: true,
                authorizationStatus: "unavailable",
                apiCalls: Self.placeholderAPICalls(status: .unsupported, message: "HealthKit type is not available on this OS or device"),
                yearlyCounts: [],
                distributionBins: [],
                records: [],
                recordArchiveData: nil
            )
            result.totalElapsedSeconds = Date().timeIntervalSince(started)
            result.timeoutConfiguredSeconds = timeoutSeconds
            result.applyTimeoutProfile(timeoutProfile)
            progress?.updateDetails(from: result)
            progress?.updateStatus(monitoredType.id, status: .failed("Unsupported"))
            return result
        }

        var result = await fetchTypeCountDataFromHK(
            monitoredType: monitoredType,
            sampleType: sampleType,
            timeoutSeconds: timeoutSeconds,
            previousTypeCount: previousTypeCount,
            archiveObservationID: archiveObservationID,
            progress: progress
        )
        result.totalElapsedSeconds = Date().timeIntervalSince(started)
        result.timeoutConfiguredSeconds = timeoutSeconds
        result.applyTimeoutProfile(timeoutProfile)
        progress?.updateDetails(from: result)

        if result.diagnosticQuality == SnapshotQuality.complete.rawValue {
            progress?.updateStatus(monitoredType.id, status: .complete, recordCount: max(result.count, 0))
        } else if result.apiCalls.contains(where: { $0.status == .timeout }) {
            progress?.updateStatus(monitoredType.id, status: .failed("Timeout"))
        } else if result.diagnosticQuality == SnapshotQuality.unauthorized.rawValue {
            progress?.updateStatus(monitoredType.id, status: .failed("Not authorized"))
        } else {
            progress?.updateStatus(monitoredType.id, status: .failed("Failed"))
        }

        return result
    }

    private func fetchTypeCountDataFromHK(
        monitoredType: MonitoredType,
        sampleType: HKSampleType,
        timeoutSeconds: TimeInterval,
        previousTypeCount: TypeCount?,
        archiveObservationID: Int64,
        progress: SnapshotFetchProgress?
    ) async -> TypeCountFetchResult {
        let dateFetchStartedAt = Date()
        let dateDeadline = Date().addingTimeInterval(timeoutSeconds)
        async let earliestTask = measureAPICall(
            queryType: "earliest_sample",
            timeoutSeconds: max(0, dateDeadline.timeIntervalSinceNow)
        ) {
            try await self.fetchEarliestDate(for: sampleType)
        } resultDescription: { date in
            Self.iso8601String(for: date)
        }
        async let latestTask = measureAPICall(
            queryType: "latest_sample",
            timeoutSeconds: max(0, dateDeadline.timeIntervalSinceNow)
        ) {
            try await self.fetchLatestDate(for: sampleType)
        } resultDescription: { date in
            Self.iso8601String(for: date)
        }
        let earliestResult = await earliestTask
        let latestResult = await latestTask
        var apiCalls = [earliestResult.apiCall, latestResult.apiCall]
        let dateFetchElapsedSeconds = Date().timeIntervalSince(dateFetchStartedAt)

        guard earliestResult.apiCall.status == .complete, latestResult.apiCall.status == .complete else {
            let status = firstImpairedStatus(in: apiCalls)
            let quality = diagnosticQuality(for: status)
            var result = TypeCountFetchResult(
                typeIdentifier: monitoredType.id,
                displayName: monitoredType.displayName,
                count: -1,
                contentHash: "",
                earliestDate: earliestResult.value ?? nil,
                latestDate: latestResult.value ?? nil,
                quality: snapshotQuality(for: status),
                diagnosticQuality: quality,
                isUnsupported: false,
                authorizationStatus: authorizationStatus(from: apiCalls),
                apiCalls: apiCalls,
                yearlyCounts: [],
                distributionBins: [],
                records: [],
                recordArchiveData: nil
            )
            result.timingBreakdown.fetchElapsedSeconds = dateFetchElapsedSeconds
            return result
        }

        let earliest = earliestResult.value ?? nil
        let latest = latestResult.value ?? nil
        let previousArchiveState = try? await archiveStore.typeCaptureState(sampleTypeIdentifier: monitoredType.id)
        let previousDistribution = PreviousDistributionState(
            typeCount: previousTypeCount,
            archiveState: previousArchiveState
        )
        let distributionResult = await measureAPICall(
            queryType: "record_import",
            timeoutSeconds: nil
        ) {
            try await self.fetchDistribution(
                for: sampleType,
                typeIdentifier: monitoredType.id,
                earliestDate: earliest,
                latestDate: latest,
                previousDistribution: previousDistribution,
                archiveObservationID: archiveObservationID,
                progress: progress
            )
        } resultDescription: { distribution in
            switch distribution.captureMode {
            case .unchangedDelta:
                return "\(distribution.totalCount) unchanged samples via empty HealthKit delta"
            case .delta:
                return "\(distribution.totalCount) samples after applying \(distribution.deltaEventCount) HealthKit delta events"
            case .initialImport:
                return "\(distribution.totalCount) samples from full HealthKit import"
            }
        }
        apiCalls.insert(distributionResult.apiCall, at: 0)

        guard distributionResult.apiCall.status == .complete, let distribution = distributionResult.value else {
            let status = distributionResult.apiCall.status
            let quality = diagnosticQuality(for: status)
            var result = TypeCountFetchResult(
                typeIdentifier: monitoredType.id,
                displayName: monitoredType.displayName,
                count: -1,
                contentHash: "",
                earliestDate: earliest,
                latestDate: latest,
                quality: snapshotQuality(for: status),
                diagnosticQuality: quality,
                isUnsupported: false,
                authorizationStatus: authorizationStatus(from: apiCalls),
                apiCalls: apiCalls,
                yearlyCounts: [],
                distributionBins: [],
                records: [],
                recordArchiveData: nil
            )
            result.timingBreakdown.fetchElapsedSeconds = dateFetchElapsedSeconds
            return result
        }

        let contentHash = distribution.contentHash ?? HashService.typeHash(
            typeIdentifier: monitoredType.id,
            recordFingerprints: distribution.records.map(\.recordFingerprint)
        )

        // YearlyCount uses Calendar.current; year attribution is local-time based.
        let yearMap: [Int: Int]
        if let cachedYearlyCounts = distribution.yearlyCounts {
            yearMap = cachedYearlyCounts
        } else {
            var computedYearMap: [Int: Int] = [:]
            for record in distribution.records {
                let year = Calendar.current.component(.year, from: record.startDate)
                computedYearMap[year, default: 0] += 1
            }
            yearMap = computedYearMap
        }
        let yearlyCounts = yearMap.map { year, yearCount in
            TypeCountFetchResult.YearlyCountData(
                year: year,
                count: yearCount,
                typeIdentifier: monitoredType.id,
                isApproximate: false
            )
        }
        progress?.updateBlockProgress(
            monitoredType.id,
            detail: "Preparing capture summary",
            recordCount: distribution.totalCount
        )
        var timingBreakdown = distribution.timingBreakdown
        timingBreakdown.fetchElapsedSeconds += dateFetchElapsedSeconds

        var result = TypeCountFetchResult(
            typeIdentifier: monitoredType.id,
            displayName: monitoredType.displayName,
            count: distribution.totalCount,
            contentHash: contentHash,
            earliestDate: earliest,
            latestDate: latest,
            quality: SnapshotQuality.complete,
            diagnosticQuality: HealthKitAPICallResult.Status.complete.rawValue,
            isUnsupported: false,
            authorizationStatus: authorizationStatus(from: apiCalls),
            apiCalls: apiCalls,
            yearlyCounts: yearlyCounts,
            distributionBins: distribution.bins.map {
                TypeCountFetchResult.DistributionBinData(
                    bucketStart: $0.start,
                    bucketEnd: $0.end,
                    count: $0.count,
                    contentHash: $0.contentHash,
                    anchorData: $0.anchorData
                )
            },
            records: [],
            recordArchiveData: distribution.recordArchiveData
        )
        result.captureMode = distribution.captureMode.diagnosticValue
        result.deltaEventCount = distribution.deltaEventCount
        result.timingBreakdown = timingBreakdown
        await persistTypeCaptureState(from: result, observationID: archiveObservationID)
        return result
    }

    private func persistTypeCaptureState(from result: TypeCountFetchResult, observationID: Int64) async {
        guard result.quality == .complete,
              result.count >= 0,
              let anchorData = result.distributionBins.last?.anchorData else {
            return
        }
        let yearlyCounts = Dictionary(uniqueKeysWithValues: result.yearlyCounts.map { ($0.year, $0.count) })
        let state = HealthArchiveTypeCaptureState(
            sampleTypeIdentifier: result.typeIdentifier,
            count: result.count,
            contentHash: result.contentHash,
            earliestDate: result.earliestDate,
            latestDate: result.latestDate,
            yearlyCounts: yearlyCounts,
            anchorData: anchorData
        )
        do {
            try await archiveStore.upsertTypeCaptureState(state, observationID: observationID)
        } catch {
            print("[HealthProbeImport] capture_state_persist_failed type=\(result.typeIdentifier) error=\(error)")
        }
    }

    // MARK: - HealthKit queries

    private func fetchDistribution(
        for sampleType: HKSampleType,
        typeIdentifier: String,
        earliestDate: Date?,
        latestDate: Date?,
        previousDistribution: PreviousDistributionState,
        archiveObservationID: Int64,
        progress: SnapshotFetchProgress?
    ) async throws -> SampleDistribution {
        var anchor = previousDistribution.globalAnchor
        let startedFromAnchor = anchor != nil
        let incrementalStrategy = DistributionCaptureConfiguration.incrementalStrategy
        var persistenceState = incrementalStrategy.makePersistenceState()
        var captureTimings = DistributionCaptureTimings.zero
        let estimatedPageCount = startedFromAnchor
            ? Self.estimatedPageCount(
                for: previousDistribution.count,
                pageLimit: incrementalStrategy.queryPageLimit
            )
            : nil
        let progressStarted = Date()
        var pageNumber = 0
        var processedEventCount = 0
        var firstDeltaPage: SampleDistributionPage?

        if anchor != nil {
            pageNumber = 1
            progress?.updateBlockProgress(
                typeIdentifier,
                detail: Self.pageProgressDetail(
                    operation: "Delta",
                    pageNumber: pageNumber,
                    estimatedPageCount: estimatedPageCount
                ),
                recordCount: previousDistribution.count,
                elapsedSeconds: 0,
                samplesPerSecond: 0
            )

            let firstPageFetchStartedAt = Date()
            let page = try await withTimeout(seconds: DistributionCaptureConfiguration.pageTimeoutSeconds) {
                try await self.fetchDistributionPage(
                    for: sampleType,
                    predicate: nil,
                    anchor: anchor,
                    limit: incrementalStrategy.queryPageLimit
                )
            }
            captureTimings.fetchElapsedSeconds += Date().timeIntervalSince(firstPageFetchStartedAt)
            anchor = page.anchor

            if !page.samples.isEmpty || !page.deletedObjects.isEmpty,
               !previousDistribution.canApplyDeltaChanges {
                progress?.updateBlockProgress(
                    typeIdentifier,
                    detail: "Delta requires full archive refresh",
                    recordCount: previousDistribution.count,
                    elapsedSeconds: Date().timeIntervalSince(progressStarted),
                    samplesPerSecond: 0
                )
                return try await fetchInitialDistributionStreaming(
                    for: sampleType,
                    typeIdentifier: typeIdentifier,
                    earliestDate: earliestDate,
                    latestDate: latestDate,
                    progressStarted: progressStarted,
                    archiveObservationID: archiveObservationID,
                    progress: progress
                )
            }

            let archiveResult = try await archivePage(
                page,
                sampleType: sampleType,
                observationID: archiveObservationID,
                progress: progress,
                typeIdentifier: typeIdentifier,
                progressDetail: "Persisting delta page \(pageNumber)",
                recordCount: previousDistribution.count,
                progressStarted: progressStarted,
                processedEventCount: processedEventCount,
                persistenceState: persistenceState
            )
            persistenceState = archiveResult.persistenceState
            captureTimings.insertElapsedSeconds += archiveResult.insertElapsedSeconds

            if page.samples.isEmpty, page.deletedObjects.isEmpty,
               let unchanged = previousDistribution.unchangedDistribution(
                    updatedAnchor: anchor,
                    typeIdentifier: typeIdentifier,
                    earliestDate: earliestDate,
                    latestDate: latestDate
               ) {
                captureTimings.addFinalization(try await finalizeUnchangedArchiveVerification(
                    sampleType: sampleType,
                    typeIdentifier: typeIdentifier,
                    recordCount: unchanged.totalCount,
                    progressStarted: progressStarted,
                    processedEventCount: processedEventCount,
                    archiveObservationID: archiveObservationID,
                    progress: progress
                ))
                progress?.updateBlockProgress(
                    typeIdentifier,
                    detail: "No HealthKit delta",
                    recordCount: unchanged.totalCount,
                    elapsedSeconds: Date().timeIntervalSince(progressStarted),
                    samplesPerSecond: 0
                )
                return SampleDistribution(
                    totalCount: unchanged.totalCount,
                    bins: unchanged.bins,
                    records: unchanged.records,
                    contentHash: unchanged.contentHash,
                    yearlyCounts: unchanged.yearlyCounts,
                    recordArchiveData: unchanged.recordArchiveData,
                    captureMode: .unchangedDelta,
                    deltaEventCount: 0,
                    timingBreakdown: captureTimings.importBreakdown
                )
            }

            firstDeltaPage = page
        }

        if !startedFromAnchor {
            return try await fetchInitialDistributionStreaming(
                for: sampleType,
                typeIdentifier: typeIdentifier,
                earliestDate: earliestDate,
                latestDate: latestDate,
                progressStarted: progressStarted,
                archiveObservationID: archiveObservationID,
                progress: progress
            )
        }

        var shouldFetchNextPage = true
        var deltaPages: [SampleDistributionPage] = []
        deltaPages.reserveCapacity(1)
        var estimatedRecordCount = previousDistribution.count

        if let firstDeltaPage {
            let firstPageApplyStartedAt = Date()
            deltaPages.append(firstDeltaPage)
            estimatedRecordCount += firstDeltaPage.samples.count - firstDeltaPage.deletedObjects.count
            let deltaApplyElapsed = Date().timeIntervalSince(firstPageApplyStartedAt)
            captureTimings.processingElapsedSeconds += deltaApplyElapsed
            captureTimings.processingDeltaApplyElapsedSeconds += deltaApplyElapsed
            processedEventCount += pageEventCount(firstDeltaPage)
            shouldFetchNextPage = firstDeltaPage.samples.count + firstDeltaPage.deletedObjects.count >= incrementalStrategy.queryPageLimit
            progress?.updateBlockProgress(
                typeIdentifier,
                detail: Self.pageProgressDetail(
                    operation: "Delta",
                    pageNumber: pageNumber,
                    estimatedPageCount: estimatedPageCount
                ),
                recordCount: max(0, estimatedRecordCount),
                elapsedSeconds: Date().timeIntervalSince(progressStarted),
                samplesPerSecond: Self.samplesPerSecond(
                    processedCount: processedEventCount,
                    elapsedSeconds: Date().timeIntervalSince(progressStarted)
                )
            )
        }

        while shouldFetchNextPage {
            pageNumber += 1
            progress?.updateBlockProgress(
                typeIdentifier,
                detail: Self.pageProgressDetail(
                    operation: anchor == nil ? "Import" : "Delta",
                    pageNumber: pageNumber,
                    estimatedPageCount: anchor == nil ? nil : estimatedPageCount
                ),
                recordCount: max(0, estimatedRecordCount),
                elapsedSeconds: Date().timeIntervalSince(progressStarted),
                samplesPerSecond: Self.samplesPerSecond(
                    processedCount: processedEventCount,
                    elapsedSeconds: Date().timeIntervalSince(progressStarted)
                )
            )

            let pageFetchStartedAt = Date()
            let page = try await withTimeout(seconds: DistributionCaptureConfiguration.pageTimeoutSeconds) {
                try await self.fetchDistributionPage(
                    for: sampleType,
                    predicate: nil,
                    anchor: anchor,
                    limit: incrementalStrategy.queryPageLimit
                )
            }
            captureTimings.fetchElapsedSeconds += Date().timeIntervalSince(pageFetchStartedAt)
            let archiveResult = try await archivePage(
                page,
                sampleType: sampleType,
                observationID: archiveObservationID,
                progress: progress,
                typeIdentifier: typeIdentifier,
                progressDetail: "Persisting delta page \(pageNumber)",
                recordCount: max(0, estimatedRecordCount),
                progressStarted: progressStarted,
                processedEventCount: processedEventCount,
                persistenceState: persistenceState
            )
            persistenceState = archiveResult.persistenceState
            captureTimings.insertElapsedSeconds += archiveResult.insertElapsedSeconds
            anchor = page.anchor

            let applyStartedAt = Date()
            deltaPages.append(page)
            estimatedRecordCount += page.samples.count - page.deletedObjects.count
            let deltaApplyElapsed = Date().timeIntervalSince(applyStartedAt)
            captureTimings.processingElapsedSeconds += deltaApplyElapsed
            captureTimings.processingDeltaApplyElapsedSeconds += deltaApplyElapsed
            processedEventCount += pageEventCount(page)
            shouldFetchNextPage = page.samples.count + page.deletedObjects.count >= incrementalStrategy.queryPageLimit
            progress?.updateBlockProgress(
                typeIdentifier,
                detail: Self.pageProgressDetail(
                    operation: anchor == nil ? "Import" : "Delta",
                    pageNumber: pageNumber,
                    estimatedPageCount: anchor == nil ? nil : estimatedPageCount
                ),
                recordCount: max(0, estimatedRecordCount),
                elapsedSeconds: Date().timeIntervalSince(progressStarted),
                samplesPerSecond: Self.samplesPerSecond(
                    processedCount: processedEventCount,
                    elapsedSeconds: Date().timeIntervalSince(progressStarted)
                )
            )
        }

        let archiveRebuildStartedAt = Date()
        let rebuiltArchive = Self.makeDeltaDistributionState(
            typeIdentifier: typeIdentifier,
            previousDistribution: previousDistribution,
            sampleType: sampleType,
            earliestDate: earliestDate,
            latestDate: latestDate,
            deltaPages: deltaPages
        )
        let archiveRebuildElapsed = Date().timeIntervalSince(archiveRebuildStartedAt)
        captureTimings.processingElapsedSeconds += archiveRebuildElapsed
        captureTimings.processingRecordArchiveRebuildElapsedSeconds += archiveRebuildElapsed

        captureTimings.addFinalization(try await finalizeArchiveVerification(
            sampleType: sampleType,
            typeIdentifier: typeIdentifier,
            recordCount: rebuiltArchive.count,
            progressStarted: progressStarted,
            processedEventCount: processedEventCount,
            archiveObservationID: archiveObservationID,
            progress: progress
        ))

        progress?.updateBlockProgress(
            typeIdentifier,
            detail: pageNumber == 1 ? "Imported 1 page" : "Imported \(pageNumber) pages",
            recordCount: rebuiltArchive.count
        )

        guard rebuiltArchive.count > 0 || anchor != nil else {
            return SampleDistribution(
                totalCount: 0,
                bins: [],
                records: [],
                contentHash: nil,
                yearlyCounts: nil,
                recordArchiveData: nil,
                captureMode: .initialImport,
                deltaEventCount: 0,
                timingBreakdown: captureTimings.importBreakdown
            )
        }

        let binStart = earliestDate ?? rebuiltArchive.earliestDate ?? previousDistribution.earliestRecordDate ?? Date()
        let rawBinEnd = latestDate ?? rebuiltArchive.latestDate ?? previousDistribution.latestRecordDate ?? binStart
        let binEnd = rawBinEnd > binStart ? rawBinEnd : binStart.addingTimeInterval(1)

        return SampleDistribution(
            totalCount: rebuiltArchive.count,
            bins: [
                SampleDistribution.Bin(
                    start: binStart,
                    end: binEnd,
                    count: rebuiltArchive.count,
                    contentHash: rebuiltArchive.contentHash,
                    anchorData: anchor.flatMap(Self.archiveAnchor(_:))
                )
            ],
            records: [],
            contentHash: rebuiltArchive.contentHash,
            yearlyCounts: nil,
            recordArchiveData: nil,
            captureMode: .delta,
            deltaEventCount: processedEventCount,
            timingBreakdown: captureTimings.importBreakdown
        )
    }

    private static func makeDeltaDistributionState(
        typeIdentifier: String,
        previousDistribution: PreviousDistributionState,
        sampleType: HKSampleType,
        earliestDate: Date?,
        latestDate: Date?,
        deltaPages: [SampleDistributionPage]
    ) -> RebuiltRecordArchive {
        let deltaSampleCount = deltaPages.reduce(0) { $0 + $1.samples.count }
        let deltaDeletedCount = deltaPages.reduce(0) { $0 + $1.deletedObjects.count }
        var replacementFingerprints: [String] = []
        replacementFingerprints.reserveCapacity(deltaSampleCount)
        var deletedUUIDHashes: [String] = []
        deletedUUIDHashes.reserveCapacity(deltaDeletedCount)

        for page in deltaPages {
            for deletedObject in page.deletedObjects {
                deletedUUIDHashes.append(HashService.sampleUUIDHash(deletedObject.uuid.uuidString))
            }

            for sample in page.samples {
                let value = recordValue(for: sample, sampleType: sampleType, typeIdentifier: typeIdentifier)
                replacementFingerprints.append(value.recordFingerprint)
            }
        }

        let recordCount = max(0, previousDistribution.count + deltaSampleCount - deltaDeletedCount)
        let effectiveEarliestDate = earliestDate ?? previousDistribution.earliestRecordDate
        let effectiveLatestDate = latestDate ?? previousDistribution.latestRecordDate
        let contentHash = HashService.archiveContentHash(
            domain: "hp:sqlite_delta_type_state:v1",
            parts: [
                typeIdentifier,
                previousDistribution.contentHash,
                String(previousDistribution.count),
                String(recordCount),
                effectiveEarliestDate.map { String(format: "%.6f", $0.timeIntervalSince1970) },
                effectiveLatestDate.map { String(format: "%.6f", $0.timeIntervalSince1970) },
                replacementFingerprints.sorted().joined(separator: "|"),
                deletedUUIDHashes.sorted().joined(separator: "|")
            ]
        )
        return RebuiltRecordArchive(
            count: recordCount,
            contentHash: contentHash,
            earliestDate: effectiveEarliestDate,
            latestDate: effectiveLatestDate,
            recordArchiveData: nil
        )
    }

    private func fetchInitialDistributionStreaming(
        for sampleType: HKSampleType,
        typeIdentifier: String,
        earliestDate: Date?,
        latestDate: Date?,
        progressStarted: Date,
        archiveObservationID: Int64,
        progress: SnapshotFetchProgress?
    ) async throws -> SampleDistribution {
        let importStrategy = DistributionCaptureConfiguration.initialImportStrategy(for: typeIdentifier)
        var persistenceState = importStrategy.makePersistenceState()
        var captureTimings = DistributionCaptureTimings.zero
        var anchor: HKQueryAnchor?
        var pageNumber = 0
        var recordCount = 0
        var processedEventCount = 0
        var firstRecordDate: Date?
        var latestRecordDate: Date?
        var yearMap: [Int: Int] = [:]
        var hashBuilder = HashService.TypeHashBuilder(typeIdentifier: typeIdentifier)
        var shouldFetchNextPage = true
        var pendingArchiveSamples: [HKSample] = []
        pendingArchiveSamples.reserveCapacity(importStrategy.initialArchiveFlushSampleLimit)

        func flushPendingArchiveSamples(pageNumber: Int) async throws {
            guard !pendingArchiveSamples.isEmpty else { return }
            let samplesToArchive = pendingArchiveSamples
            pendingArchiveSamples.removeAll(keepingCapacity: true)
            let archiveResult = try await archivePage(
                SampleDistributionPage(samples: samplesToArchive, deletedObjects: [], anchor: nil),
                sampleType: sampleType,
                observationID: archiveObservationID,
                progress: progress,
                typeIdentifier: typeIdentifier,
                progressDetail: "Persisting import pages through \(pageNumber)",
                recordCount: nil,
                progressStarted: progressStarted,
                processedEventCount: processedEventCount,
                persistenceState: persistenceState
            )
            persistenceState = archiveResult.persistenceState
            captureTimings.insertElapsedSeconds += archiveResult.insertElapsedSeconds
        }

        while shouldFetchNextPage {
            pageNumber += 1
            let elapsedBeforePage = Date().timeIntervalSince(progressStarted)
            progress?.updateBlockProgress(
                typeIdentifier,
                detail: Self.pageProgressDetail(
                    operation: "Import",
                    pageNumber: pageNumber,
                    estimatedPageCount: nil
                ),
                recordCount: recordCount,
                elapsedSeconds: elapsedBeforePage,
                samplesPerSecond: Self.samplesPerSecond(
                    processedCount: processedEventCount,
                    elapsedSeconds: elapsedBeforePage
                )
            )

            let pageFetchStartedAt = Date()
            let page = try await withTimeout(seconds: DistributionCaptureConfiguration.pageTimeoutSeconds) {
                try await self.fetchDistributionPage(
                    for: sampleType,
                    predicate: nil,
                    anchor: anchor,
                    limit: importStrategy.queryPageLimit
                )
            }
            captureTimings.fetchElapsedSeconds += Date().timeIntervalSince(pageFetchStartedAt)
            anchor = page.anchor
            pendingArchiveSamples.append(contentsOf: page.samples)
            if !page.deletedObjects.isEmpty {
                try await flushPendingArchiveSamples(pageNumber: pageNumber)
                let archiveResult = try await archivePage(
                    SampleDistributionPage(samples: [], deletedObjects: page.deletedObjects, anchor: page.anchor),
                    sampleType: sampleType,
                    observationID: archiveObservationID,
                    progress: progress,
                    typeIdentifier: typeIdentifier,
                    progressDetail: "Persisting import deletes page \(pageNumber)",
                    recordCount: nil,
                    progressStarted: progressStarted,
                    processedEventCount: processedEventCount,
                    persistenceState: persistenceState
                )
                persistenceState = archiveResult.persistenceState
                captureTimings.insertElapsedSeconds += archiveResult.insertElapsedSeconds
            }

            let processStartedAt = Date()
            for sample in page.samples {
                autoreleasepool {
                    let value = Self.recordValue(for: sample, sampleType: sampleType, typeIdentifier: typeIdentifier)
                    hashBuilder.append(recordFingerprint: value.recordFingerprint)
                    yearMap[Calendar.current.component(.year, from: value.startDate), default: 0] += 1
                    firstRecordDate = min(firstRecordDate ?? value.startDate, value.startDate)
                    latestRecordDate = max(latestRecordDate ?? value.endDate, value.endDate)
                    recordCount += 1
                }
            }
            let recordProcessingElapsed = Date().timeIntervalSince(processStartedAt)
            captureTimings.processingElapsedSeconds += recordProcessingElapsed
            captureTimings.processingInitialRecordElapsedSeconds += recordProcessingElapsed

            processedEventCount += pageEventCount(page)
            shouldFetchNextPage = page.samples.count + page.deletedObjects.count >= importStrategy.queryPageLimit
            if pendingArchiveSamples.count >= importStrategy.initialArchiveFlushSampleLimit || !shouldFetchNextPage {
                try await flushPendingArchiveSamples(pageNumber: pageNumber)
            }
            let elapsedAfterPage = Date().timeIntervalSince(progressStarted)
            progress?.updateBlockProgress(
                typeIdentifier,
                detail: Self.pageProgressDetail(
                    operation: "Import",
                    pageNumber: pageNumber,
                    estimatedPageCount: nil
                ),
                recordCount: recordCount,
                elapsedSeconds: elapsedAfterPage,
                samplesPerSecond: Self.samplesPerSecond(
                    processedCount: processedEventCount,
                    elapsedSeconds: elapsedAfterPage
                )
            )
            await Task.yield()
        }

        let finalizeHashStartedAt = Date()
        let contentHash = hashBuilder.finalize()
        let hashFinalizeElapsed = Date().timeIntervalSince(finalizeHashStartedAt)
        captureTimings.processingElapsedSeconds += hashFinalizeElapsed
        progress?.updateBlockProgress(
            typeIdentifier,
            detail: pageNumber == 1 ? "Imported 1 page" : "Imported \(pageNumber) pages",
            recordCount: recordCount,
            elapsedSeconds: Date().timeIntervalSince(progressStarted),
            samplesPerSecond: Self.samplesPerSecond(
                processedCount: processedEventCount,
                elapsedSeconds: Date().timeIntervalSince(progressStarted)
            )
        )

        captureTimings.addFinalization(try await finalizeArchiveVerification(
            sampleType: sampleType,
            typeIdentifier: typeIdentifier,
            recordCount: recordCount,
            progressStarted: progressStarted,
            processedEventCount: processedEventCount,
            archiveObservationID: archiveObservationID,
            progress: progress
        ))

        guard recordCount > 0 || anchor != nil else {
            return SampleDistribution(
                totalCount: 0,
                bins: [],
                records: [],
                contentHash: nil,
                yearlyCounts: nil,
                recordArchiveData: nil,
                captureMode: .initialImport,
                deltaEventCount: 0,
                timingBreakdown: captureTimings.importBreakdown
            )
        }

        let binStart = earliestDate ?? firstRecordDate ?? Date()
        let rawBinEnd = latestDate ?? latestRecordDate ?? binStart
        let binEnd = rawBinEnd > binStart ? rawBinEnd : binStart.addingTimeInterval(1)

        return SampleDistribution(
            totalCount: recordCount,
            bins: [
                SampleDistribution.Bin(
                    start: binStart,
                    end: binEnd,
                    count: recordCount,
                    contentHash: contentHash,
                    anchorData: anchor.flatMap(Self.archiveAnchor(_:))
                )
            ],
            records: [],
            contentHash: contentHash,
            yearlyCounts: yearMap,
            recordArchiveData: nil,
            captureMode: .initialImport,
            deltaEventCount: processedEventCount,
            timingBreakdown: captureTimings.importBreakdown
        )
    }

    private static func recordValue(
        for sample: HKSample,
        sampleType: HKSampleType,
        typeIdentifier: String
    ) -> HealthRecordValue {
        HealthRecordValue(
            typeIdentifier: typeIdentifier,
            sampleUUIDHash: HashService.sampleUUIDHash(sample.uuid.uuidString),
            recordFingerprint: HashService.sampleFingerprint(
                typeIdentifier: sampleType.identifier,
                sampleUUID: sample.uuid.uuidString,
                startDate: sample.startDate,
                endDate: sample.endDate
            ),
            startDate: sample.startDate,
            endDate: sample.endDate,
            displayValue: nil
        )
    }

    private func pageEventCount(_ page: SampleDistributionPage) -> Int {
        page.samples.count + page.deletedObjects.count
    }

    private static func estimatedPageCount(for recordCount: Int, pageLimit: Int) -> Int {
        let count = max(recordCount, 0)
        let normalizedPageLimit = max(pageLimit, 1)
        return max(1, (count + normalizedPageLimit - 1) / normalizedPageLimit)
    }

    private static func samplesPerSecond(processedCount: Int, elapsedSeconds: TimeInterval) -> Double {
        guard elapsedSeconds > 0, processedCount > 0 else { return 0 }
        return Double(processedCount) / elapsedSeconds
    }

    private func finalizeUnchangedArchiveVerification(
        sampleType: HKSampleType,
        typeIdentifier: String,
        recordCount: Int,
        progressStarted: Date,
        processedEventCount: Int,
        archiveObservationID: Int64,
        progress: SnapshotFetchProgress?
    ) async throws -> HealthArchiveFinalizationBreakdown {
        try await finalizeArchiveVerification(
            sampleType: sampleType,
            typeIdentifier: typeIdentifier,
            recordCount: recordCount,
            progressStarted: progressStarted,
            processedEventCount: processedEventCount,
            archiveObservationID: archiveObservationID,
            progress: progress,
            markVerification: {
                try await self.archiveStore.markUnchangedVerification(
                    sampleType: sampleType,
                    verifiedAt: Date(),
                    observationID: archiveObservationID
                )
            }
        )
    }

    private func finalizeArchiveVerification(
        sampleType: HKSampleType,
        typeIdentifier: String,
        recordCount: Int,
        progressStarted: Date,
        processedEventCount: Int,
        archiveObservationID: Int64,
        progress: SnapshotFetchProgress?,
        markVerification: (() async throws -> HealthArchiveFinalizationBreakdown)? = nil
    ) async throws -> HealthArchiveFinalizationBreakdown {
        let elapsedBeforeFinalize = Date().timeIntervalSince(progressStarted)
        progress?.updateBlockProgress(
            typeIdentifier,
            detail: "Finalizing archive aggregates",
            recordCount: recordCount,
            elapsedSeconds: elapsedBeforeFinalize,
            samplesPerSecond: Self.samplesPerSecond(
                processedCount: processedEventCount,
                elapsedSeconds: elapsedBeforeFinalize
            )
        )

        let verificationStartedAt = Date()
        let breakdown: HealthArchiveFinalizationBreakdown
        if let markVerification {
            breakdown = try await markVerification()
        } else {
            breakdown = try await archiveStore.markVerification(
                sampleType: sampleType,
                verifiedAt: Date(),
                observationID: archiveObservationID
            )
        }
        let finalizeElapsed = Date().timeIntervalSince(verificationStartedAt)
        var normalizedBreakdown = breakdown
        normalizedBreakdown.totalElapsedSeconds = finalizeElapsed

        let elapsedAfterFinalize = Date().timeIntervalSince(progressStarted)
        progress?.updateBlockProgress(
            typeIdentifier,
            detail: "Archive aggregates finalized",
            recordCount: recordCount,
            elapsedSeconds: elapsedAfterFinalize,
            samplesPerSecond: Self.samplesPerSecond(
                processedCount: processedEventCount,
                elapsedSeconds: elapsedAfterFinalize
            )
        )

        return normalizedBreakdown
    }

    private static func pageProgressDetail(
        operation: String,
        pageNumber: Int,
        estimatedPageCount: Int?
    ) -> String {
        guard let estimatedPageCount else {
            return "\(operation) page \(pageNumber) (total unknown)"
        }

        if pageNumber <= estimatedPageCount {
            return "\(operation) page \(pageNumber) of ~\(estimatedPageCount)"
        }

        return "\(operation) page \(pageNumber) of ~\(estimatedPageCount)+"
    }

    private func fetchDistributionPage(
        for sampleType: HKSampleType,
        predicate: NSPredicate?,
        anchor: HKQueryAnchor?,
        limit: Int
    ) async throws -> SampleDistributionPage {
        let box = HealthKitQueryContinuationBox<SampleDistributionPage>()
        nonisolated(unsafe) let queryPredicate = predicate
        let queryLimit = max(limit, 1)
        return try await withTaskCancellationHandler {
            try await withCheckedThrowingContinuation { continuation in
                box.setContinuation(continuation)
                let query = HKAnchoredObjectQuery(
                    type: sampleType,
                    predicate: queryPredicate,
                    anchor: anchor,
                    limit: queryLimit
                ) { _, samples, deletedObjects, newAnchor, error in
                    if let error {
                        box.resume(throwing: error)
                        return
                    }

                    box.resume(
                        returning: SampleDistributionPage(
                            samples: samples ?? [],
                            deletedObjects: deletedObjects ?? [],
                            anchor: newAnchor
                        )
                    )
                }
                box.setQuery(query, store: store)
                store.execute(query)
            }
        } onCancel: {
            box.cancel()
        }
    }

    private func archivePage(
        _ page: SampleDistributionPage,
        sampleType: HKSampleType,
        observationID: Int64,
        progress: SnapshotFetchProgress? = nil,
        typeIdentifier: String? = nil,
        progressDetail: String? = nil,
        recordCount: Int? = nil,
        progressStarted: Date? = nil,
        processedEventCount: Int? = nil,
        persistenceState: DistributionPagePersistenceState
    ) async throws -> DistributionPageArchiveResult {
        var persistenceState = persistenceState
        let completedEventCountBeforePage = processedEventCount ?? 0
        var persistedSampleCount = 0
        var persistedDeletedCount = 0
        var insertElapsedSeconds: TimeInterval = 0
        let observedAt = Date()
        if !page.samples.isEmpty {
            var batchStart = 0
            while batchStart < page.samples.count {
                let chunkSize = min(
                    max(persistenceState.currentWriteChunkSize, persistenceState.minimumWriteChunkSize),
                    page.samples.count - batchStart
                )
                let batchEnd = min(
                    batchStart + chunkSize,
                    page.samples.count
                )
                let sampleBatch = Array(page.samples[batchStart..<batchEnd])
                if let progress, let typeIdentifier, let progressDetail {
                    let detail = page.samples.count <= chunkSize
                        ? progressDetail
                        : "\(progressDetail) (\(batchStart + 1)-\(batchEnd)/\(page.samples.count))"
                    progress.updateBlockProgress(
                        typeIdentifier,
                        detail: detail,
                        recordCount: recordCount.map { $0 + persistedSampleCount },
                        elapsedSeconds: progressStarted.map { Date().timeIntervalSince($0) },
                        samplesPerSecond: {
                            guard let progressStarted else { return nil }
                            return Self.samplesPerSecond(
                                processedCount: completedEventCountBeforePage + persistedSampleCount + persistedDeletedCount,
                                elapsedSeconds: Date().timeIntervalSince(progressStarted)
                            )
                        }()
                    )
                }
                let batchStartedAt = Date()
                _ = try await archiveStore.upsertSamples(
                    sampleBatch,
                    observedAt: observedAt,
                    observationID: observationID
                )
                let batchElapsedSeconds = Date().timeIntervalSince(batchStartedAt)
                insertElapsedSeconds += batchElapsedSeconds
                persistedSampleCount += sampleBatch.count
                persistenceState.registerBatchDuration(batchElapsedSeconds)
                batchStart = batchEnd
                await Task.yield()
            }
        }
        if !page.deletedObjects.isEmpty {
            let deletedHashes = page.deletedObjects.map { HashService.sampleUUIDHash($0.uuid.uuidString) }
            var deleteBatchStart = 0
            while deleteBatchStart < deletedHashes.count {
                let deleteBatchEnd = min(
                    deleteBatchStart + DistributionCaptureConfiguration.deleteBatchSize,
                    deletedHashes.count
                )
                let deleteBatch = Array(deletedHashes[deleteBatchStart..<deleteBatchEnd])
                if let progress, let typeIdentifier, let progressDetail {
                    let detail = deletedHashes.count <= DistributionCaptureConfiguration.deleteBatchSize
                        ? "\(progressDetail) (deletes \(deleteBatchEnd)/\(deletedHashes.count))"
                        : "\(progressDetail) (deletes \(deleteBatchStart + 1)-\(deleteBatchEnd)/\(deletedHashes.count))"
                    progress.updateBlockProgress(
                        typeIdentifier,
                        detail: detail,
                        recordCount: recordCount.map { $0 + persistedSampleCount },
                        elapsedSeconds: progressStarted.map { Date().timeIntervalSince($0) },
                        samplesPerSecond: {
                            guard let progressStarted else { return nil }
                            return Self.samplesPerSecond(
                                processedCount: completedEventCountBeforePage + persistedSampleCount + persistedDeletedCount,
                                elapsedSeconds: Date().timeIntervalSince(progressStarted)
                            )
                        }()
                    )
                }
                let batchStartedAt = Date()
                let deletedCount = try await archiveStore.recordDisappearances(
                    sampleUUIDHashes: deleteBatch,
                    sampleTypeIdentifier: sampleType.identifier,
                    observedMissingAt: observedAt,
                    observationID: observationID
                )
                insertElapsedSeconds += Date().timeIntervalSince(batchStartedAt)
                _ = deletedCount
                persistedDeletedCount += deleteBatch.count
                deleteBatchStart = deleteBatchEnd
                await Task.yield()
            }
        }
        return DistributionPageArchiveResult(
            persistenceState: persistenceState,
            persistedSampleCount: persistedSampleCount,
            persistedDeletedCount: persistedDeletedCount,
            insertElapsedSeconds: insertElapsedSeconds
        )
    }

    private static func archiveAnchor(_ anchor: HKQueryAnchor) -> Data? {
        try? NSKeyedArchiver.archivedData(withRootObject: anchor, requiringSecureCoding: true)
    }

    private static func unarchiveAnchor(_ data: Data?) -> HKQueryAnchor? {
        guard let data else { return nil }
        return try? NSKeyedUnarchiver.unarchivedObject(ofClass: HKQueryAnchor.self, from: data)
    }

    private static func displayValue(for sample: HKSample) -> String? {
        if let quantitySample = sample as? HKQuantitySample {
            return quantityDisplayValue(for: quantitySample)
        }

        if let categorySample = sample as? HKCategorySample {
            return categoryDisplayValue(for: categorySample)
        }

        if let workout = sample as? HKWorkout {
            return workoutDisplayValue(for: workout)
        }

        return nil
    }

    private static func quantityDisplayValue(for sample: HKQuantitySample) -> String? {
        let identifier = sample.quantityType.identifier
        switch identifier {
        case HKQuantityTypeIdentifier.stepCount.rawValue:
            return format(sample.quantity.doubleValue(for: .count()), unit: "")
        case HKQuantityTypeIdentifier.distanceWalkingRunning.rawValue:
            let meters = sample.quantity.doubleValue(for: .meter())
            return meters >= 1_000
                ? "\(format(meters / 1_000, maximumFractionDigits: 2)) km"
                : "\(format(meters, maximumFractionDigits: 0)) m"
        case HKQuantityTypeIdentifier.activeEnergyBurned.rawValue:
            return "\(format(sample.quantity.doubleValue(for: .kilocalorie()), maximumFractionDigits: 0)) kcal"
        case HKQuantityTypeIdentifier.appleExerciseTime.rawValue:
            return "\(format(sample.quantity.doubleValue(for: .minute()), maximumFractionDigits: 0)) min"
        case HKQuantityTypeIdentifier.heartRate.rawValue,
             HKQuantityTypeIdentifier.restingHeartRate.rawValue:
            return "\(format(sample.quantity.doubleValue(for: HKUnit.count().unitDivided(by: .minute())), maximumFractionDigits: 0)) bpm"
        case HKQuantityTypeIdentifier.respiratoryRate.rawValue:
            return "\(format(sample.quantity.doubleValue(for: HKUnit.count().unitDivided(by: .minute())), maximumFractionDigits: 1)) breaths/min"
        case HKQuantityTypeIdentifier.environmentalAudioExposure.rawValue,
             HKQuantityTypeIdentifier.headphoneAudioExposure.rawValue:
            return "\(format(sample.quantity.doubleValue(for: .decibelAWeightedSoundPressureLevel()), maximumFractionDigits: 1)) dB"
        case HKQuantityTypeIdentifier.bodyMass.rawValue:
            return "\(format(sample.quantity.doubleValue(for: HKUnit.gramUnit(with: .kilo)), maximumFractionDigits: 1)) kg"
        case HKQuantityTypeIdentifier.vo2Max.rawValue:
            let unit = HKUnit.literUnit(with: .milli)
                .unitDivided(by: HKUnit.gramUnit(with: .kilo))
                .unitDivided(by: .minute())
            return "\(format(sample.quantity.doubleValue(for: unit), maximumFractionDigits: 1)) mL/kg/min"
        default:
            return nil
        }
    }

    private static func categoryDisplayValue(for sample: HKCategorySample) -> String {
        switch sample.categoryType.identifier {
        case HKCategoryTypeIdentifier.appleStandHour.rawValue:
            if sample.value == HKCategoryValueAppleStandHour.stood.rawValue {
                return "Stood"
            }
            if sample.value == HKCategoryValueAppleStandHour.idle.rawValue {
                return "Idle"
            }
            return "Stand hour \(sample.value)"
        case HKCategoryTypeIdentifier.sleepAnalysis.rawValue:
            return sleepValueLabel(sample.value)
        case HKCategoryTypeIdentifier.highHeartRateEvent.rawValue:
            return "High heart rate event"
        default:
            return "Category value \(sample.value)"
        }
    }

    private static func workoutDisplayValue(for workout: HKWorkout) -> String {
        let duration = format(workout.duration / 60, maximumFractionDigits: 0)
        return "\(workoutActivityName(workout.workoutActivityType)), \(duration) min"
    }

    private static func workoutActivityName(_ type: HKWorkoutActivityType) -> String {
        switch type {
        case .walking: return "Walking"
        case .running: return "Running"
        case .cycling: return "Cycling"
        case .swimming: return "Swimming"
        case .traditionalStrengthTraining: return "Strength training"
        case .functionalStrengthTraining: return "Functional strength training"
        case .highIntensityIntervalTraining: return "HIIT"
        case .yoga: return "Yoga"
        case .hiking: return "Hiking"
        case .mindAndBody: return "Mind and body"
        case .other: return "Workout"
        default: return "Workout \(type.rawValue)"
        }
    }

    private static func sleepValueLabel(_ value: Int) -> String {
        if value == HKCategoryValueSleepAnalysis.inBed.rawValue { return "In bed" }
        if value == HKCategoryValueSleepAnalysis.asleepUnspecified.rawValue { return "Asleep" }
        if value == HKCategoryValueSleepAnalysis.awake.rawValue { return "Awake" }
        if value == HKCategoryValueSleepAnalysis.asleepCore.rawValue { return "Core sleep" }
        if value == HKCategoryValueSleepAnalysis.asleepDeep.rawValue { return "Deep sleep" }
        if value == HKCategoryValueSleepAnalysis.asleepREM.rawValue { return "REM sleep" }
        return "Sleep value \(value)"
    }

    private static func format(_ value: Double, maximumFractionDigits: Int = 2, unit: String? = nil) -> String {
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        formatter.maximumFractionDigits = maximumFractionDigits
        formatter.minimumFractionDigits = 0
        let formatted = formatter.string(from: NSNumber(value: value)) ?? "\(value)"
        if let unit, !unit.isEmpty {
            return "\(formatted) \(unit)"
        }
        return formatted
    }

    private func fetchEarliestDate(for sampleType: HKSampleType) async throws -> Date? {
        try await withCheckedThrowingContinuation { continuation in
            let query = HKSampleQuery(
                sampleType: sampleType,
                predicate: nil,
                limit: 1,
                sortDescriptors: [NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: true)]
            ) { _, samples, error in
                if let error { continuation.resume(throwing: error); return }
                continuation.resume(returning: samples?.first?.startDate)
            }
            store.execute(query)
        }
    }

    private func fetchLatestDate(for sampleType: HKSampleType) async throws -> Date? {
        try await withCheckedThrowingContinuation { continuation in
            let query = HKSampleQuery(
                sampleType: sampleType,
                predicate: nil,
                limit: 1,
                sortDescriptors: [NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)]
            ) { _, samples, error in
                if let error { continuation.resume(throwing: error); return }
                continuation.resume(returning: samples?.first?.startDate)
            }
            store.execute(query)
        }
    }

    // MARK: - Timeout profiles

    private func timeoutProfile(for monitoredType: MonitoredType) -> LocalMetricTimeoutProfile {
        LocalMetricTimeoutProfileStore.profile(for: monitoredType)
    }

    private func timeoutForFetch(
        profile: LocalMetricTimeoutProfile,
        adaptiveTimeoutsEnabled: Bool,
        timeoutMultiplier: Double
    ) -> TimeInterval {
        let base = adaptiveTimeoutsEnabled ? profile.effectiveTimeout : Self.defaultInitialTimeoutSeconds
        return min(max(base * timeoutMultiplier, Self.defaultInitialTimeoutSeconds), Self.maximumTimeoutSeconds)
    }

    private func updateTimeoutProfile(
        _ profile: inout LocalMetricTimeoutProfile,
        with result: TypeCountFetchResult,
        monitoredType: MonitoredType
    ) {
        if result.quality == .complete {
            profile.recordSuccess(elapsed: result.totalElapsedSeconds, displayName: monitoredType.displayName)
        } else if result.apiCalls.contains(where: { $0.status == .timeout }) {
            profile.recordTimeout(elapsed: result.totalElapsedSeconds, displayName: monitoredType.displayName)
        } else {
            profile.displayName = monitoredType.displayName
        }
    }

    // MARK: - Query diagnostics

    private struct APICallMeasurement<Value: Sendable>: Sendable {
        let value: Value?
        let apiCall: HealthKitAPICallResult
    }

    private func measureAPICall<Value: Sendable>(
        queryType: String,
        timeoutSeconds: TimeInterval?,
        operation: @escaping @Sendable () async throws -> Value,
        resultDescription: @escaping @Sendable (Value) -> String
    ) async -> APICallMeasurement<Value> {
        let started = Date()
        do {
            let value: Value
            if let timeoutSeconds {
                guard timeoutSeconds > 0 else { throw CancellationError() }
                value = try await withTimeout(seconds: timeoutSeconds, operation: operation)
            } else {
                // Initial full imports can legitimately run far longer than a fixed
                // wall clock cap. Keep per-page HealthKit timeouts, but do not
                // abort the whole import while pages continue to make progress.
                value = try await operation()
            }
            return APICallMeasurement(
                value: value,
                apiCall: HealthKitAPICallResult(
                    queryType: queryType,
                    status: .complete,
                    elapsedSeconds: Date().timeIntervalSince(started),
                    resultValue: resultDescription(value)
                )
            )
        } catch {
            let failure = Self.apiFailure(for: error)
            let nsError = error as NSError
            return APICallMeasurement(
                value: nil,
                apiCall: HealthKitAPICallResult(
                    queryType: queryType,
                    status: failure.status,
                    elapsedSeconds: Date().timeIntervalSince(started),
                    resultValue: nil,
                    errorCode: failure.errorCode ?? "\(nsError.code)",
                    errorDomain: failure.errorDomain ?? nsError.domain,
                    errorDescription: failure.errorDescription ?? nsError.localizedDescription,
                    failureKind: failure.failureKind,
                    cancellationReason: failure.cancellationReason
                )
            )
        }
    }

    private static func apiFailure(for error: Error) -> (
        status: HealthKitAPICallResult.Status,
        failureKind: String,
        errorDomain: String?,
        errorCode: String?,
        errorDescription: String?,
        cancellationReason: String?
    ) {
        if error is CancellationError {
            return (
                .timeout,
                "internal cancellation",
                "HealthProbe",
                "perTypeTimeout",
                "HealthProbe cancelled this query after the per-type timeout",
                "per-type timeout reached"
            )
        }

        let nsError = error as NSError
        if nsError.domain == NSURLErrorDomain && nsError.code == NSURLErrorTimedOut {
            return (.timeout, "timeout", nil, nil, nil, nil)
        }

        if (error as? HKError)?.code == .errorAuthorizationDenied {
            return (.unauthorized, "HealthKit error", nil, nil, nil, nil)
        }

        return (.failed, "HealthKit error", nil, nil, nil, nil)
    }

    private func authorizationStatus(from apiCalls: [HealthKitAPICallResult]) -> String {
        if apiCalls.contains(where: { $0.status == .complete }) {
            return "granted"
        }
        if apiCalls.contains(where: { $0.status == .unauthorized }) {
            return "denied"
        }
        return HealthKitAPICallResult.Status.unknown.rawValue
    }

    private func snapshotQuality(for status: HealthKitAPICallResult.Status) -> SnapshotQuality {
        status == .unauthorized ? .unauthorized : .failed
    }

    private func diagnosticQuality(for status: HealthKitAPICallResult.Status) -> String {
        switch status {
        case .complete:
            return HealthKitAPICallResult.Status.complete.rawValue
        case .unauthorized:
            return HealthKitAPICallResult.Status.unauthorized.rawValue
        case .unsupported:
            return HealthKitAPICallResult.Status.unsupported.rawValue
        case .timeout:
            return SnapshotQuality.failed.rawValue
        case .failed:
            return HealthKitAPICallResult.Status.failed.rawValue
        case .unknown:
            return HealthKitAPICallResult.Status.unknown.rawValue
        }
    }

    private func firstImpairedStatus(in apiCalls: [HealthKitAPICallResult]) -> HealthKitAPICallResult.Status {
        let statuses = apiCalls.map(\.status)
        if statuses.contains(.unauthorized) { return .unauthorized }
        if statuses.contains(.timeout) { return .timeout }
        if statuses.contains(.unsupported) { return .unsupported }
        if statuses.contains(.failed) { return .failed }
        return .unknown
    }

    private static func placeholderAPICalls(status: HealthKitAPICallResult.Status, message: String) -> [HealthKitAPICallResult] {
        [
            placeholderAPICall(queryType: "record_import", status: status, message: message),
            placeholderAPICall(queryType: "earliest_sample", status: status, message: message),
            placeholderAPICall(queryType: "latest_sample", status: status, message: message)
        ]
    }

    private static func placeholderAPICall(
        queryType: String,
        status: HealthKitAPICallResult.Status,
        message: String
    ) -> HealthKitAPICallResult {
        HealthKitAPICallResult(
            queryType: queryType,
            status: status,
            elapsedSeconds: 0,
            resultValue: nil,
            errorCode: "none",
            errorDomain: "none",
            errorDescription: message,
            failureKind: status == .unknown ? "not run" : status.rawValue,
            cancellationReason: "none"
        )
    }

    private static func iso8601String(for date: Date?) -> String {
        guard let date else { return "none" }
        return ISO8601DateFormatter().string(from: date)
    }

    // MARK: - Quality aggregation

    func deriveSnapshotQuality(from typeCounts: [TypeCount]) -> SnapshotQuality {
        guard !typeCounts.isEmpty else { return .failed }
        if typeCounts.contains(where: { $0.quality == .loading }) { return .loading }
        let allUnauthorized = typeCounts.allSatisfy { $0.quality == .unauthorized }
        if allUnauthorized { return .unauthorized }
        let anyImpaired = typeCounts.contains { $0.quality == .failed || $0.quality == .unauthorized }
        if anyImpaired { return .partial }
        return .complete
    }

    // MARK: - Chain helpers

    private func findPreviousSnapshot(deviceID: String, excluding id: UUID, context: ModelContext) -> HealthSnapshot? {
        var descriptor = FetchDescriptor<HealthSnapshot>(
            predicate: #Predicate<HealthSnapshot> { $0.deviceID == deviceID && $0.id != id },
            sortBy: [SortDescriptor(\.localSequenceNumber, order: .reverse)]
        )
        descriptor.fetchLimit = 1
        return try? context.fetch(descriptor).first
    }

    private func fetchSnapshot(id: UUID, context: ModelContext) -> HealthSnapshot? {
        var descriptor = FetchDescriptor<HealthSnapshot>(
            predicate: #Predicate<HealthSnapshot> { $0.id == id }
        )
        descriptor.fetchLimit = 1
        return try? context.fetch(descriptor).first
    }

    private func isStoreEmpty(context: ModelContext) -> Bool {
        var descriptor = FetchDescriptor<HealthSnapshot>()
        descriptor.fetchLimit = 1
        return (try? context.fetch(descriptor).isEmpty) ?? true
    }

    // MARK: - Device metadata

    private func hardwareModel() -> String {
        var size = 0
        sysctlbyname("hw.machine", nil, &size, nil, 0)
        var machine = [CChar](repeating: 0, count: size)
        sysctlbyname("hw.machine", &machine, &size, nil, 0)
        return String(cString: machine)
    }

    private func appBuildVersion() -> String {
        let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? ""
        let build = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? ""
        return "\(version) (\(build))"
    }

    // MARK: - Timeout utility

    private func withTimeout<T: Sendable>(seconds: TimeInterval, operation: @escaping @Sendable () async throws -> T) async throws -> T {
        try await withThrowingTaskGroup(of: T.self) { group in
            group.addTask { try await operation() }
            group.addTask {
                try await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000))
                throw CancellationError()
            }
            do {
                let result = try await group.next()!
                group.cancelAll()
                return result
            } catch {
                group.cancelAll()
                throw error
            }
        }
    }

    // MARK: - Type registry

    private static func buildAllTypes() -> [MonitoredType] {
        var result: [MonitoredType] = []

        func addQty(_ id: HKQuantityTypeIdentifier, _ name: String, _ cat: TypeCategory, on: Bool) {
            let t = HKObjectType.quantityType(forIdentifier: id)
            result.append(MonitoredType(id: t?.identifier ?? id.rawValue, displayName: name, category: cat, isEnabledByDefault: on, objectType: t))
        }

        func addQtyRaw(_ rawIdentifier: String, _ name: String, _ cat: TypeCategory, on: Bool = false) {
            let id = HKQuantityTypeIdentifier(rawValue: rawIdentifier)
            let t = HKObjectType.quantityType(forIdentifier: id)
            result.append(MonitoredType(id: t?.identifier ?? rawIdentifier, displayName: name, category: cat, isEnabledByDefault: on, objectType: t))
        }

        func addCat(_ id: HKCategoryTypeIdentifier, _ name: String, _ cat: TypeCategory, on: Bool) {
            let t = HKObjectType.categoryType(forIdentifier: id)
            result.append(MonitoredType(id: t?.identifier ?? id.rawValue, displayName: name, category: cat, isEnabledByDefault: on, objectType: t))
        }

        func addCatRaw(_ rawIdentifier: String, _ name: String, _ cat: TypeCategory, on: Bool = false) {
            let id = HKCategoryTypeIdentifier(rawValue: rawIdentifier)
            let t = HKObjectType.categoryType(forIdentifier: id)
            result.append(MonitoredType(id: t?.identifier ?? rawIdentifier, displayName: name, category: cat, isEnabledByDefault: on, objectType: t))
        }

        let workout = HKObjectType.workoutType()
        result.append(MonitoredType(id: workout.identifier, displayName: "Workouts", category: .activity, isEnabledByDefault: true, objectType: workout))

        addQty(.stepCount,              "Steps",                          .activity,    on: true)
        addQty(.distanceWalkingRunning, "Walking + Running Distance",     .activity,    on: true)
        addQty(.activeEnergyBurned,     "Active Energy",                  .activity,    on: true)
        addQty(.appleExerciseTime,      "Exercise Minutes",               .activity,    on: true)
        addCat(.appleStandHour,         "Stand Hours",                    .activity,    on: true)
        addQtyRaw("HKQuantityTypeIdentifierBasalEnergyBurned", "Basal Energy", .activity)
        addQtyRaw("HKQuantityTypeIdentifierFlightsClimbed", "Flights Climbed", .activity)
        addQtyRaw("HKQuantityTypeIdentifierAppleMoveTime", "Move Time", .activity)
        addQtyRaw("HKQuantityTypeIdentifierAppleStandTime", "Stand Time", .activity)
        addQtyRaw("HKQuantityTypeIdentifierDistanceCycling", "Cycling Distance", .activity)
        addQtyRaw("HKQuantityTypeIdentifierDistanceSwimming", "Swimming Distance", .activity)
        addQtyRaw("HKQuantityTypeIdentifierSwimmingStrokeCount", "Swimming Stroke Count", .activity)
        addQtyRaw("HKQuantityTypeIdentifierDistanceDownhillSnowSports", "Downhill Snow Sports Distance", .activity)
        addQtyRaw("HKQuantityTypeIdentifierPushCount", "Wheelchair Pushes", .activity)
        addQtyRaw("HKQuantityTypeIdentifierDistanceWheelchair", "Wheelchair Distance", .activity)

        addQty(.heartRate,              "Heart Rate",                     .heart,       on: true)
        addQty(.restingHeartRate,       "Resting Heart Rate",             .heart,       on: true)
        addCat(.highHeartRateEvent,     "High Heart Rate Notifications",  .heart,       on: true)
        addQtyRaw("HKQuantityTypeIdentifierWalkingHeartRateAverage", "Walking Heart Rate Average", .heart)
        addQtyRaw("HKQuantityTypeIdentifierHeartRateVariabilitySDNN", "Heart Rate Variability", .heart)
        addQtyRaw("HKQuantityTypeIdentifierAtrialFibrillationBurden", "Atrial Fibrillation Burden", .heart)
        addCatRaw("HKCategoryTypeIdentifierLowHeartRateEvent", "Low Heart Rate Notifications", .heart)
        addCatRaw("HKCategoryTypeIdentifierIrregularHeartRhythmEvent", "Irregular Rhythm Notifications", .heart)

        addQty(.respiratoryRate,        "Respiratory Rate",               .respiratory, on: true)
        addQtyRaw("HKQuantityTypeIdentifierOxygenSaturation", "Blood Oxygen", .respiratory)
        addQtyRaw("HKQuantityTypeIdentifierForcedVitalCapacity", "Forced Vital Capacity", .respiratory)
        addQtyRaw("HKQuantityTypeIdentifierForcedExpiratoryVolume1", "Forced Expiratory Volume, 1 sec", .respiratory)
        addQtyRaw("HKQuantityTypeIdentifierPeakExpiratoryFlowRate", "Peak Expiratory Flow Rate", .respiratory)
        addQtyRaw("HKQuantityTypeIdentifierInhalerUsage", "Inhaler Usage", .respiratory)

        addCat(.sleepAnalysis,          "Sleep",                          .sleep,       on: true)

        addQty(.environmentalAudioExposure, "Environmental Sound Levels", .hearing,     on: false)
        addQty(.headphoneAudioExposure,     "Headphone Audio Levels",     .hearing,     on: false)
        addCatRaw("HKCategoryTypeIdentifierHeadphoneAudioExposureEvent", "Headphone Audio Notifications", .hearing)
        addCatRaw("HKCategoryTypeIdentifierEnvironmentalAudioExposureEvent", "Environmental Audio Notifications", .hearing)

        addQty(.bodyMass, "Body Mass", .body, on: false)
        addQty(.vo2Max,   "VO2 Max",   .body, on: false)
        addQtyRaw("HKQuantityTypeIdentifierBodyMassIndex", "Body Mass Index", .body)
        addQtyRaw("HKQuantityTypeIdentifierBodyFatPercentage", "Body Fat Percentage", .body)
        addQtyRaw("HKQuantityTypeIdentifierHeight", "Height", .body)
        addQtyRaw("HKQuantityTypeIdentifierLeanBodyMass", "Lean Body Mass", .body)
        addQtyRaw("HKQuantityTypeIdentifierWaistCircumference", "Waist Circumference", .body)
        addQtyRaw("HKQuantityTypeIdentifierBodyTemperature", "Body Temperature", .body)
        addQtyRaw("HKQuantityTypeIdentifierBasalBodyTemperature", "Basal Body Temperature", .body)
        addQtyRaw("HKQuantityTypeIdentifierBloodPressureSystolic", "Blood Pressure Systolic", .body)
        addQtyRaw("HKQuantityTypeIdentifierBloodPressureDiastolic", "Blood Pressure Diastolic", .body)
        addQtyRaw("HKQuantityTypeIdentifierBloodGlucose", "Blood Glucose", .body)
        addQtyRaw("HKQuantityTypeIdentifierInsulinDelivery", "Insulin Delivery", .body)
        addQtyRaw("HKQuantityTypeIdentifierPeripheralPerfusionIndex", "Peripheral Perfusion Index", .body)
        addQtyRaw("HKQuantityTypeIdentifierElectrodermalActivity", "Electrodermal Activity", .body)

        addQtyRaw("HKQuantityTypeIdentifierWalkingSpeed", "Walking Speed", .mobility)
        addQtyRaw("HKQuantityTypeIdentifierWalkingStepLength", "Walking Step Length", .mobility)
        addQtyRaw("HKQuantityTypeIdentifierWalkingAsymmetryPercentage", "Walking Asymmetry", .mobility)
        addQtyRaw("HKQuantityTypeIdentifierWalkingDoubleSupportPercentage", "Double Support Time", .mobility)
        addQtyRaw("HKQuantityTypeIdentifierSixMinuteWalkTestDistance", "Six-Minute Walk Distance", .mobility)
        addQtyRaw("HKQuantityTypeIdentifierStairAscentSpeed", "Stair Ascent Speed", .mobility)
        addQtyRaw("HKQuantityTypeIdentifierStairDescentSpeed", "Stair Descent Speed", .mobility)
        addQtyRaw("HKQuantityTypeIdentifierAppleWalkingSteadiness", "Walking Steadiness", .mobility)
        addCatRaw("HKCategoryTypeIdentifierAppleWalkingSteadinessEvent", "Walking Steadiness Notifications", .mobility)

        addQtyRaw("HKQuantityTypeIdentifierDietaryEnergyConsumed", "Dietary Energy", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietaryWater", "Water", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietaryProtein", "Protein", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietaryCarbohydrates", "Carbohydrates", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietaryFiber", "Fiber", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietarySugar", "Sugar", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietaryFatTotal", "Total Fat", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietaryFatSaturated", "Saturated Fat", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietaryFatMonounsaturated", "Monounsaturated Fat", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietaryFatPolyunsaturated", "Polyunsaturated Fat", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietaryCholesterol", "Cholesterol", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietarySodium", "Sodium", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietaryPotassium", "Potassium", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietaryCalcium", "Calcium", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietaryIron", "Iron", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietaryMagnesium", "Magnesium", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietaryZinc", "Zinc", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietaryVitaminA", "Vitamin A", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietaryVitaminB6", "Vitamin B6", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietaryVitaminB12", "Vitamin B12", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietaryVitaminC", "Vitamin C", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietaryVitaminD", "Vitamin D", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietaryVitaminE", "Vitamin E", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietaryVitaminK", "Vitamin K", .nutrition)
        addQtyRaw("HKQuantityTypeIdentifierDietaryCaffeine", "Caffeine", .nutrition)

        addCatRaw("HKCategoryTypeIdentifierMenstrualFlow", "Menstrual Flow", .reproductive)
        addCatRaw("HKCategoryTypeIdentifierIntermenstrualBleeding", "Intermenstrual Bleeding", .reproductive)
        addCatRaw("HKCategoryTypeIdentifierOvulationTestResult", "Ovulation Test Result", .reproductive)
        addCatRaw("HKCategoryTypeIdentifierCervicalMucusQuality", "Cervical Mucus Quality", .reproductive)
        addCatRaw("HKCategoryTypeIdentifierSexualActivity", "Sexual Activity", .reproductive)
        addCatRaw("HKCategoryTypeIdentifierPregnancy", "Pregnancy", .reproductive)
        addCatRaw("HKCategoryTypeIdentifierLactation", "Lactation", .reproductive)
        addCatRaw("HKCategoryTypeIdentifierContraceptive", "Contraceptive", .reproductive)

        addCatRaw("HKCategoryTypeIdentifierAbdominalCramps", "Abdominal Cramps", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierAcne", "Acne", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierAppetiteChanges", "Appetite Changes", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierBloating", "Bloating", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierBreastPain", "Breast Pain", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierChestTightnessOrPain", "Chest Tightness or Pain", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierChills", "Chills", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierConstipation", "Constipation", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierCoughing", "Coughing", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierDiarrhea", "Diarrhea", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierDizziness", "Dizziness", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierFatigue", "Fatigue", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierFever", "Fever", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierHeadache", "Headache", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierHeartburn", "Heartburn", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierHotFlashes", "Hot Flashes", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierLossOfSmell", "Loss of Smell", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierLossOfTaste", "Loss of Taste", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierLowerBackPain", "Lower Back Pain", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierMemoryLapse", "Memory Lapse", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierMoodChanges", "Mood Changes", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierNausea", "Nausea", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierPelvicPain", "Pelvic Pain", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat", "Rapid or Pounding Heartbeat", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierRunnyNose", "Runny Nose", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierShortnessOfBreath", "Shortness of Breath", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierSinusCongestion", "Sinus Congestion", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierSkippedHeartbeat", "Skipped Heartbeat", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierSleepChanges", "Sleep Changes", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierSoreThroat", "Sore Throat", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierVaginalDryness", "Vaginal Dryness", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierVomiting", "Vomiting", .symptoms)
        addCatRaw("HKCategoryTypeIdentifierWheezing", "Wheezing", .symptoms)

        addCatRaw("HKCategoryTypeIdentifierMindfulSession", "Mindful Sessions", .other)
        addCatRaw("HKCategoryTypeIdentifierToothbrushingEvent", "Toothbrushing", .other)
        addCatRaw("HKCategoryTypeIdentifierHandwashingEvent", "Handwashing", .other)

        return result
    }
}

private struct SampleDistribution: Sendable {
    enum CaptureMode: Sendable {
        case initialImport
        case delta
        case unchangedDelta

        var diagnosticValue: String {
            switch self {
            case .initialImport:
                return "initialImport"
            case .delta:
                return "delta"
            case .unchangedDelta:
                return "unchangedDelta"
            }
        }
    }

    struct Bin: Sendable {
        let start: Date
        let end: Date
        let count: Int
        let contentHash: String
        let anchorData: Data?
    }
    let totalCount: Int
    let bins: [Bin]
    let records: [HealthRecordValue]
    let contentHash: String?
    let yearlyCounts: [Int: Int]?
    let recordArchiveData: Data?
    let captureMode: CaptureMode
    let deltaEventCount: Int
    let timingBreakdown: ImportTimingBreakdown
}

private struct SampleDistributionPage: Sendable {
    let samples: [HKSample]
    let deletedObjects: [HKDeletedObject]
    let anchor: HKQueryAnchor?
}

private struct RebuiltRecordArchive: Sendable {
    let count: Int
    let contentHash: String
    let earliestDate: Date?
    let latestDate: Date?
    let recordArchiveData: Data?
}

private final class HealthKitQueryContinuationBox<Value: Sendable>: @unchecked Sendable {
    private let lock = NSLock()
    nonisolated(unsafe) private var continuation: CheckedContinuation<Value, Error>?
    nonisolated(unsafe) private var query: HKQuery?
    nonisolated(unsafe) private weak var store: HKHealthStore?
    nonisolated(unsafe) private var didResume = false

    nonisolated func setContinuation(_ continuation: CheckedContinuation<Value, Error>) {
        let shouldCancel: Bool
        lock.lock()
        if didResume {
            shouldCancel = true
        } else {
            shouldCancel = false
            self.continuation = continuation
        }
        lock.unlock()

        if shouldCancel {
            continuation.resume(throwing: CancellationError())
        }
    }

    nonisolated func setQuery(_ query: HKQuery, store: HKHealthStore) {
        lock.lock()
        self.query = query
        self.store = store
        let shouldStop = didResume
        lock.unlock()

        if shouldStop {
            store.stop(query)
        }
    }

    nonisolated func resume(returning value: Value) {
        complete { $0.resume(returning: value) }
    }

    nonisolated func resume(throwing error: Error) {
        complete { $0.resume(throwing: error) }
    }

    nonisolated func cancel() {
        let queryToStop: HKQuery?
        let storeToStop: HKHealthStore?
        lock.lock()
        queryToStop = query
        storeToStop = store
        lock.unlock()

        if let queryToStop, let storeToStop {
            storeToStop.stop(queryToStop)
        }

        resume(throwing: CancellationError())
    }

    nonisolated private func complete(_ resume: (CheckedContinuation<Value, Error>) -> Void) {
        let continuationToResume: CheckedContinuation<Value, Error>?
        lock.lock()
        if didResume {
            continuationToResume = nil
        } else {
            didResume = true
            continuationToResume = continuation
            continuation = nil
        }
        lock.unlock()

        if let continuationToResume {
            resume(continuationToResume)
        }
    }
}

private struct PreviousDistributionState: Sendable {
    struct Bin: Sendable {
        let bucketStart: Date
        let bucketEnd: Date
        let anchorData: Data?

        var anchor: HKQueryAnchor? {
            guard let anchorData else { return nil }
            return try? NSKeyedUnarchiver.unarchivedObject(ofClass: HKQueryAnchor.self, from: anchorData)
        }
    }

    let typeIdentifier: String
    let count: Int
    let contentHash: String
    let earliestRecordDate: Date?
    let latestRecordDate: Date?
    let recordArchiveData: Data?
    let yearlyCounts: [Int: Int]
    let bins: [Bin]

    var globalAnchor: HKQueryAnchor? {
        guard bins.count == 1 else { return nil }
        return bins[0].anchor
    }

    var canApplyDeltaChanges: Bool {
        count == 0 || !contentHash.isEmpty
    }

    init(typeCount: TypeCount?, archiveState: HealthArchiveTypeCaptureState?) {
        let typeCountBins = typeCount?.distributionBins ?? []
        self.typeIdentifier = typeCount?.typeIdentifier ?? archiveState?.sampleTypeIdentifier ?? ""
        self.count = typeCount?.count ?? archiveState?.count ?? 0
        self.contentHash = typeCount?.contentHash ?? archiveState?.contentHash ?? ""
        self.earliestRecordDate = typeCount?.earliestDate ?? archiveState?.earliestDate
        self.latestRecordDate = typeCount?.latestDate ?? archiveState?.latestDate
        self.recordArchiveData = typeCount?.recordArchiveData
        let typeCountYearlyCounts = Dictionary(
            uniqueKeysWithValues: (typeCount?.yearlyCounts ?? []).map { ($0.year, $0.count) }
        )
        self.yearlyCounts = typeCountYearlyCounts.isEmpty
            ? archiveState?.yearlyCounts ?? [:]
            : typeCountYearlyCounts
        if typeCountBins.count == 1, typeCountBins[0].anchorData != nil {
            self.bins = typeCountBins.map {
                Bin(
                    bucketStart: $0.bucketStart,
                    bucketEnd: $0.bucketEnd,
                    anchorData: $0.anchorData
                )
            }
        } else if let archiveState, let anchorData = archiveState.anchorData {
            let bucketStart = archiveState.earliestDate ?? Date()
            let rawBucketEnd = archiveState.latestDate ?? bucketStart
            self.bins = [
                Bin(
                    bucketStart: bucketStart,
                    bucketEnd: rawBucketEnd > bucketStart ? rawBucketEnd : bucketStart.addingTimeInterval(1),
                    anchorData: anchorData
                )
            ]
        } else {
            self.bins = []
        }
    }

    func unchangedDistribution(
        updatedAnchor: HKQueryAnchor?,
        typeIdentifier fallbackTypeIdentifier: String,
        earliestDate: Date?,
        latestDate: Date?
    ) -> SampleDistribution? {
        guard count >= 0,
              count == 0 || !contentHash.isEmpty else {
            return nil
        }

        let binStart = earliestDate ?? earliestRecordDate ?? Date()
        let rawBinEnd = latestDate ?? latestRecordDate ?? binStart
        let binEnd = rawBinEnd > binStart ? rawBinEnd : binStart.addingTimeInterval(1)
        let effectiveTypeIdentifier = typeIdentifier.isEmpty ? fallbackTypeIdentifier : typeIdentifier
        let effectiveContentHash = contentHash.isEmpty
            ? HashService.typeHash(typeIdentifier: effectiveTypeIdentifier, recordFingerprints: [])
            : contentHash

        return SampleDistribution(
            totalCount: count,
            bins: [
                SampleDistribution.Bin(
                    start: binStart,
                    end: binEnd,
                    count: count,
                    contentHash: effectiveContentHash,
                    anchorData: updatedAnchor.flatMap(Self.archiveAnchor(_:))
                )
            ],
            records: [],
            contentHash: effectiveContentHash,
            yearlyCounts: yearlyCounts,
            recordArchiveData: recordArchiveData,
            captureMode: .unchangedDelta,
            deltaEventCount: 0,
            timingBreakdown: .zero
        )
    }

    private nonisolated static func archiveAnchor(_ anchor: HKQueryAnchor) -> Data? {
        try? NSKeyedArchiver.archivedData(withRootObject: anchor, requiringSecureCoding: true)
    }
}

private struct TypeCountFetchResult: Sendable {
    struct YearlyCountData: Sendable {
        let year: Int
        let count: Int
        let typeIdentifier: String
        let isApproximate: Bool
    }
    struct RecordData: Sendable {
        let typeIdentifier: String
        let sampleUUIDHash: String
        let recordFingerprint: String
        let startDate: Date
        let endDate: Date
        let displayValue: String?
    }
    struct DistributionBinData: Sendable {
        let bucketStart: Date
        let bucketEnd: Date
        let count: Int
        let contentHash: String
        let anchorData: Data?
    }

    let typeIdentifier: String
    let displayName: String
    let count: Int
    let contentHash: String
    let earliestDate: Date?
    let latestDate: Date?
    let quality: SnapshotQuality
    let diagnosticQuality: String
    let isUnsupported: Bool
    let authorizationStatus: String
    let apiCalls: [HealthKitAPICallResult]
    let yearlyCounts: [YearlyCountData]
    let distributionBins: [DistributionBinData]
    let records: [RecordData]
    let recordArchiveData: Data?
    var captureMode: String = "unavailable"
    var deltaEventCount: Int = 0
    var timeoutConfiguredSeconds: TimeInterval = 0
    var totalElapsedSeconds: TimeInterval = 0
    var timeoutMode: String = "default"
    var lastSuccessfulElapsed: TimeInterval = 0
    var learnedTimeout: TimeInterval = 0
    var suggestedRetryTimeout: TimeInterval = 0
    var timeoutCount: Int = 0
    var successCount: Int = 0
    var timingBreakdown: ImportTimingBreakdown = .zero

    mutating func applyTimeoutProfile(_ profile: LocalMetricTimeoutProfile) {
        timeoutMode = profile.timeoutMode
        lastSuccessfulElapsed = profile.lastSuccessfulElapsed
        learnedTimeout = profile.effectiveTimeout
        suggestedRetryTimeout = profile.suggestedRetryTimeout
        timeoutCount = profile.timeoutCount
        successCount = profile.successCount
    }

    @MainActor
    func makeTypeCount() -> TypeCount {
        let typeCount = TypeCount(
            typeIdentifier: typeIdentifier,
            displayName: displayName,
            count: count,
            quality: quality
        )
        typeCount.contentHash = contentHash
        typeCount.earliestDate = earliestDate
        typeCount.latestDate = latestDate
        typeCount.isUnsupported = isUnsupported

        typeCount.yearlyCounts = yearlyCounts.map { yearlyCountData in
            YearlyCount(
                year: yearlyCountData.year,
                count: yearlyCountData.count,
                typeIdentifier: yearlyCountData.typeIdentifier,
                isApproximate: yearlyCountData.isApproximate
            )
        }

        typeCount.distributionBins = distributionBins.map { binData in
            var bin = TypeDistributionBin(
                bucketStart: binData.bucketStart,
                bucketEnd: binData.bucketEnd,
                count: binData.count
            )
            bin.contentHash = binData.contentHash
            bin.anchorData = binData.anchorData
            return bin
        }

        if let recordArchiveData {
            typeCount.recordArchiveData = recordArchiveData
        } else if !records.isEmpty {
            typeCount.setRecordValues(records.map { recordData in
                HealthRecordValue(
                    typeIdentifier: recordData.typeIdentifier,
                    sampleUUIDHash: recordData.sampleUUIDHash,
                    recordFingerprint: recordData.recordFingerprint,
                    startDate: recordData.startDate,
                    endDate: recordData.endDate,
                    displayValue: recordData.displayValue
                )
            })
        }

        return typeCount
    }
}

private extension SnapshotFetchProgress {
    func updateDetails(from result: TypeCountFetchResult) {
        updateDetails(
            result.typeIdentifier,
            quality: result.diagnosticQuality,
            recordCount: result.count,
            isUnsupported: result.isUnsupported,
            authorizationStatus: result.authorizationStatus,
            earliestDate: result.earliestDate,
            latestDate: result.latestDate,
            yearlyCounts: result.yearlyCounts.map {
                SnapshotFetchProgress.YearlyCountProgress(
                    year: $0.year,
                    count: $0.count,
                    isApproximate: $0.isApproximate
                )
            },
            apiCallDetails: result.apiCalls,
            timeoutConfiguredSeconds: result.timeoutConfiguredSeconds,
            totalElapsedSeconds: result.totalElapsedSeconds,
            timeoutMode: result.timeoutMode,
            lastSuccessfulElapsed: result.lastSuccessfulElapsed,
            learnedTimeout: result.learnedTimeout,
            suggestedRetryTimeout: result.suggestedRetryTimeout,
            timeoutCount: result.timeoutCount,
            successCount: result.successCount,
            timingBreakdown: result.timingBreakdown,
            captureMode: result.captureMode,
            deltaEventCount: result.deltaEventCount
        )
    }

    func updateTimeoutProfile(from profile: LocalMetricTimeoutProfile, for typeID: String) {
        updateTimeoutProfile(
            typeID,
            timeoutMode: profile.timeoutMode,
            lastSuccessfulElapsed: profile.lastSuccessfulElapsed,
            learnedTimeout: profile.effectiveTimeout,
            suggestedRetryTimeout: profile.suggestedRetryTimeout,
            timeoutCount: profile.timeoutCount,
            successCount: profile.successCount
        )
    }
}

struct DistributionCaptureStrategy: Equatable {
    let queryPageLimit: Int
    let initialWriteChunkSize: Int
    let initialArchiveFlushSampleLimit: Int
    let minimumWriteChunkSize: Int
    let slowBatchThresholdSeconds: TimeInterval
    let severeBatchThresholdSeconds: TimeInterval

    func makePersistenceState() -> DistributionPagePersistenceState {
        DistributionPagePersistenceState(
            currentWriteChunkSize: initialWriteChunkSize,
            maximumWriteChunkSize: initialWriteChunkSize,
            minimumWriteChunkSize: minimumWriteChunkSize,
            slowBatchThresholdSeconds: slowBatchThresholdSeconds,
            severeBatchThresholdSeconds: severeBatchThresholdSeconds
        )
    }
}

struct DistributionPagePersistenceState: Equatable {
    var currentWriteChunkSize: Int
    let maximumWriteChunkSize: Int
    let minimumWriteChunkSize: Int
    let slowBatchThresholdSeconds: TimeInterval
    let severeBatchThresholdSeconds: TimeInterval

    mutating func registerBatchDuration(_ duration: TimeInterval) {
        if duration >= severeBatchThresholdSeconds {
            currentWriteChunkSize = max(minimumWriteChunkSize, currentWriteChunkSize / 2)
            return
        }
        if duration >= slowBatchThresholdSeconds {
            currentWriteChunkSize = max(minimumWriteChunkSize, currentWriteChunkSize - max(minimumWriteChunkSize / 2, 50))
            return
        }
        if duration <= 0.35, currentWriteChunkSize < maximumWriteChunkSize {
            currentWriteChunkSize = min(maximumWriteChunkSize, currentWriteChunkSize + max(minimumWriteChunkSize / 2, 50))
        }
    }
}

struct DistributionPageArchiveResult: Equatable {
    let persistenceState: DistributionPagePersistenceState
    let persistedSampleCount: Int
    let persistedDeletedCount: Int
    let insertElapsedSeconds: TimeInterval
}

private struct DistributionCaptureTimings: Sendable, Equatable {
    var fetchElapsedSeconds: TimeInterval = 0
    var processingElapsedSeconds: TimeInterval = 0
    var processingDeltaApplyElapsedSeconds: TimeInterval = 0
    var processingRecordArchiveRebuildElapsedSeconds: TimeInterval = 0
    var processingInitialRecordElapsedSeconds: TimeInterval = 0
    var processingRecordArchiveFinalizeElapsedSeconds: TimeInterval = 0
    var insertElapsedSeconds: TimeInterval = 0
    var finalizeElapsedSeconds: TimeInterval = 0
    var finalizeEventCountElapsedSeconds: TimeInterval = 0
    var finalizeTypeSummaryElapsedSeconds: TimeInterval = 0
    var finalizeDailyAggregateElapsedSeconds: TimeInterval = 0
    var finalizeDailyAggregateBucketLookupElapsedSeconds: TimeInterval = 0
    var finalizeDailyAggregateCopyElapsedSeconds: TimeInterval = 0
    var finalizeDailyAggregateDeleteElapsedSeconds: TimeInterval = 0
    var finalizeDailyAggregateRebuildElapsedSeconds: TimeInterval = 0
    var finalizeDailyAggregateInsertElapsedSeconds: TimeInterval = 0
    var finalizeDailyAggregateOtherElapsedSeconds: TimeInterval = 0
    var finalizeRunUpdateElapsedSeconds: TimeInterval = 0
    var finalizeOtherElapsedSeconds: TimeInterval = 0

    static let zero = DistributionCaptureTimings()

    mutating func addFinalization(_ breakdown: HealthArchiveFinalizationBreakdown) {
        finalizeElapsedSeconds += breakdown.totalElapsedSeconds
        finalizeEventCountElapsedSeconds += breakdown.eventCountElapsedSeconds
        finalizeTypeSummaryElapsedSeconds += breakdown.typeSummaryElapsedSeconds
        finalizeDailyAggregateElapsedSeconds += breakdown.dailyAggregateElapsedSeconds
        finalizeDailyAggregateBucketLookupElapsedSeconds += breakdown.dailyAggregateBucketLookupElapsedSeconds
        finalizeDailyAggregateCopyElapsedSeconds += breakdown.dailyAggregateCopyElapsedSeconds
        finalizeDailyAggregateDeleteElapsedSeconds += breakdown.dailyAggregateDeleteElapsedSeconds
        finalizeDailyAggregateRebuildElapsedSeconds += breakdown.dailyAggregateRebuildElapsedSeconds
        finalizeDailyAggregateInsertElapsedSeconds += breakdown.dailyAggregateInsertElapsedSeconds
        finalizeDailyAggregateOtherElapsedSeconds += breakdown.dailyAggregateOtherElapsedSeconds
        finalizeRunUpdateElapsedSeconds += breakdown.runUpdateElapsedSeconds
        finalizeOtherElapsedSeconds += breakdown.otherElapsedSeconds
    }

    var importBreakdown: ImportTimingBreakdown {
        ImportTimingBreakdown(
            fetchElapsedSeconds: fetchElapsedSeconds,
            processingElapsedSeconds: processingElapsedSeconds,
            processingDeltaApplyElapsedSeconds: processingDeltaApplyElapsedSeconds,
            processingRecordArchiveRebuildElapsedSeconds: processingRecordArchiveRebuildElapsedSeconds,
            processingInitialRecordElapsedSeconds: processingInitialRecordElapsedSeconds,
            processingRecordArchiveFinalizeElapsedSeconds: processingRecordArchiveFinalizeElapsedSeconds,
            insertElapsedSeconds: insertElapsedSeconds,
            finalizeElapsedSeconds: finalizeElapsedSeconds,
            finalizeEventCountElapsedSeconds: finalizeEventCountElapsedSeconds,
            finalizeTypeSummaryElapsedSeconds: finalizeTypeSummaryElapsedSeconds,
            finalizeDailyAggregateElapsedSeconds: finalizeDailyAggregateElapsedSeconds,
            finalizeDailyAggregateBucketLookupElapsedSeconds: finalizeDailyAggregateBucketLookupElapsedSeconds,
            finalizeDailyAggregateCopyElapsedSeconds: finalizeDailyAggregateCopyElapsedSeconds,
            finalizeDailyAggregateDeleteElapsedSeconds: finalizeDailyAggregateDeleteElapsedSeconds,
            finalizeDailyAggregateRebuildElapsedSeconds: finalizeDailyAggregateRebuildElapsedSeconds,
            finalizeDailyAggregateInsertElapsedSeconds: finalizeDailyAggregateInsertElapsedSeconds,
            finalizeDailyAggregateOtherElapsedSeconds: finalizeDailyAggregateOtherElapsedSeconds,
            finalizeRunUpdateElapsedSeconds: finalizeRunUpdateElapsedSeconds,
            finalizeOtherElapsedSeconds: finalizeOtherElapsedSeconds
        )
    }
}

enum DistributionCaptureConfiguration {
    static let pageTimeoutSeconds: TimeInterval = 60
    static let incrementalStrategy = DistributionCaptureStrategy(
        queryPageLimit: 10_000,
        initialWriteChunkSize: 2_000,
        initialArchiveFlushSampleLimit: 2_000,
        minimumWriteChunkSize: 500,
        slowBatchThresholdSeconds: 2.5,
        severeBatchThresholdSeconds: 6
    )

    private static let veryHighVolumeTypeIdentifiers: Set<String> = [
        HKQuantityTypeIdentifier.heartRate.rawValue,
    ]

    private static let highVolumeTypeIdentifiers: Set<String> = [
        HKQuantityTypeIdentifier.stepCount.rawValue,
        HKQuantityTypeIdentifier.distanceWalkingRunning.rawValue,
        HKQuantityTypeIdentifier.activeEnergyBurned.rawValue,
        HKQuantityTypeIdentifier.appleExerciseTime.rawValue,
        HKCategoryTypeIdentifier.sleepAnalysis.rawValue,
        HKQuantityTypeIdentifier.headphoneAudioExposure.rawValue,
        HKQuantityTypeIdentifier.environmentalAudioExposure.rawValue
    ]

    static func initialImportStrategy(for typeIdentifier: String) -> DistributionCaptureStrategy {
        if veryHighVolumeTypeIdentifiers.contains(typeIdentifier) {
            return DistributionCaptureStrategy(
                queryPageLimit: 2_000,
                initialWriteChunkSize: 5_000,
                initialArchiveFlushSampleLimit: 10_000,
                minimumWriteChunkSize: 500,
                slowBatchThresholdSeconds: 2.5,
                severeBatchThresholdSeconds: 6
            )
        }

        if highVolumeTypeIdentifiers.contains(typeIdentifier) {
            return DistributionCaptureStrategy(
                queryPageLimit: 5_000,
                initialWriteChunkSize: 2_500,
                initialArchiveFlushSampleLimit: 10_000,
                minimumWriteChunkSize: 500,
                slowBatchThresholdSeconds: 1.75,
                severeBatchThresholdSeconds: 4.5
            )
        }

        return DistributionCaptureStrategy(
            queryPageLimit: 20_000,
            initialWriteChunkSize: 5_000,
            initialArchiveFlushSampleLimit: 5_000,
            minimumWriteChunkSize: 500,
            slowBatchThresholdSeconds: 2.5,
            severeBatchThresholdSeconds: 6
        )
    }

    static let deleteBatchSize = 100
}
