import SwiftUI
import HealthKit
import HealthKitExtensions

struct SearchHealthStoreView: View {

    @State
    var start: Date = .now.addingTimeInterval(-86400)

    @State
    var end: Date = .now

    @State
    var quantity: HKQuantityTypeIdentifier = .heartRate

    @State
    var isRunningQuery = false

    @State
    var samples: [HKQuantitySample] = []

    private let store = HKHealthStore()

    var body: some View {
        VStack {
            DatePicker("Start date", selection: $start)
            DatePicker("End date", selection: $end)
            Picker("Quantity", selection: $quantity) {
                ForEach(HKQuantityTypeIdentifier.allCases) { id in
                    Text(id.description).tag(id)
                }

            }
            Button(action: performQuery) {
                Text("Search")
                    .padding()
            }
            .disabled(isRunningQuery)
            Text("\(samples.count) samples found")
        }
        .padding()
        .navigationTitle("Search")
    }

    func performQuery() {
        isRunningQuery = true
        Task {
            let samples = try await queryHealthStore()
            DispatchQueue.main.async {
                self.samples = samples
                self.isRunningQuery = false
            }
        }
    }

    func queryHealthStore() async throws -> [HKQuantitySample] {
        let sortByDate = NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: true)
        let predicate = HKQuery.predicateForSamples(withStart: start, end: end, options: [])

        let samples = try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<[HKQuantitySample], Error>) in
            let query = HKSampleQuery(
                sampleType: HKQuantityType(quantity),
                predicate: predicate,
                limit: HKObjectQueryNoLimit,
                sortDescriptors: [sortByDate]) { query, samples, error in
                if let error = error {
                    continuation.resume(throwing: error)
                    return
                }
                guard let samples = samples else {
                    continuation.resume(returning: [])
                    return
                }
                continuation.resume(returning: samples as! [HKQuantitySample])
            }
            store.execute(query)
        }
        return samples
    }
}

#Preview {
    SearchHealthStoreView()
}

extension HKQuantityTypeIdentifier: @retroactive Identifiable {

    public var id: String {
        rawValue
    }
}
