import Foundation
import Capacitor

@objc(HealthPlugin)
public class HealthPlugin: CAPPlugin, CAPBridgedPlugin {
    private let pluginVersion: String = "8.7.0"
    public let identifier = "HealthPlugin"
    public let jsName = "Health"
    public let pluginMethods: [CAPPluginMethod] = [
        CAPPluginMethod(name: "isAvailable", returnType: CAPPluginReturnPromise),
        CAPPluginMethod(name: "requestAuthorization", returnType: CAPPluginReturnPromise),
        CAPPluginMethod(name: "checkAuthorization", returnType: CAPPluginReturnPromise),
        CAPPluginMethod(name: "readSamples", returnType: CAPPluginReturnPromise),
        CAPPluginMethod(name: "saveSample", returnType: CAPPluginReturnPromise),
        CAPPluginMethod(name: "getPluginVersion", returnType: CAPPluginReturnPromise),
        CAPPluginMethod(name: "openHealthConnectSettings", returnType: CAPPluginReturnPromise),
        CAPPluginMethod(name: "showPrivacyPolicy", returnType: CAPPluginReturnPromise),
        CAPPluginMethod(name: "queryWorkouts", returnType: CAPPluginReturnPromise),
        CAPPluginMethod(name: "queryAggregated", returnType: CAPPluginReturnPromise)
    ]

    private let implementation = Health()

    @objc func isAvailable(_ call: CAPPluginCall) {
        call.resolve(implementation.availabilityPayload())
    }

    @objc func requestAuthorization(_ call: CAPPluginCall) {
        let read = (call.getArray("read") as? [String]) ?? []
        let write = (call.getArray("write") as? [String]) ?? []
        // `requestHistoryAccess` is Android-only (READ_HEALTH_DATA_HISTORY). HealthKit has no
        // equivalent permission and no 30-day read cap, so we intentionally ignore it here and
        // leave `historyAccessAuthorized` out of the returned status.

        implementation.requestAuthorization(readIdentifiers: read, writeIdentifiers: write) { result in
            DispatchQueue.main.async {
                switch result {
                case let .success(payload):
                    call.resolve(payload.toDictionary())
                case let .failure(error):
                    call.reject(error.localizedDescription, nil, error)
                }
            }
        }
    }

    @objc func checkAuthorization(_ call: CAPPluginCall) {
        let read = (call.getArray("read") as? [String]) ?? []
        let write = (call.getArray("write") as? [String]) ?? []
        // `requestHistoryAccess` is Android-only; intentionally ignored on iOS (see requestAuthorization).

        implementation.checkAuthorization(readIdentifiers: read, writeIdentifiers: write) { result in
            DispatchQueue.main.async {
                switch result {
                case let .success(payload):
                    call.resolve(payload.toDictionary())
                case let .failure(error):
                    call.reject(error.localizedDescription, nil, error)
                }
            }
        }
    }

    @objc func readSamples(_ call: CAPPluginCall) {
        guard let dataType = call.getString("dataType") else {
            call.reject("dataType is required")
            return
        }

        let startDate = call.getString("startDate")
        let endDate = call.getString("endDate")
        let limit = call.getInt("limit")
        let ascending = call.getBool("ascending") ?? false

        do {
            try implementation.readSamples(
                dataTypeIdentifier: dataType,
                startDateString: startDate,
                endDateString: endDate,
                limit: limit,
                ascending: ascending
            ) { result in
                DispatchQueue.main.async {
                    switch result {
                    case let .success(samples):
                        call.resolve(["samples": samples])
                    case let .failure(error):
                        call.reject(error.localizedDescription, nil, error)
                    }
                }
            }
        } catch {
            call.reject(error.localizedDescription, nil, error)
        }
    }

    @objc func saveSample(_ call: CAPPluginCall) {
        guard let dataType = call.getString("dataType") else {
            call.reject("dataType is required")
            return
        }

        guard let value = call.getDouble("value") else {
            call.reject("value is required")
            return
        }

        let unit = call.getString("unit")
        let startDate = call.getString("startDate")
        let endDate = call.getString("endDate")
        let metadataAny = call.getObject("metadata") as? [String: Any]
        let metadata = metadataAny?.reduce(into: [String: String]()) { result, entry in
            if let stringValue = entry.value as? String {
                result[entry.key] = stringValue
            }
        }
        
        let systolic = call.getDouble("systolic")
        let diastolic = call.getDouble("diastolic")

        do {
            try implementation.saveSample(
                dataTypeIdentifier: dataType,
                value: value,
                unitIdentifier: unit,
                startDateString: startDate,
                endDateString: endDate,
                metadata: metadata,
                systolic: systolic,
                diastolic: diastolic
            ) { result in
                DispatchQueue.main.async {
                    switch result {
                    case .success:
                        call.resolve()
                    case let .failure(error):
                        call.reject(error.localizedDescription, nil, error)
                    }
                }
            }
        } catch {
            call.reject(error.localizedDescription, nil, error)
        }
    }

    @objc func getPluginVersion(_ call: CAPPluginCall) {
        call.resolve(["version": self.pluginVersion])
    }

    @objc func openHealthConnectSettings(_ call: CAPPluginCall) {
        // No-op on iOS - Health Connect is Android only
        call.resolve()
    }

    @objc func showPrivacyPolicy(_ call: CAPPluginCall) {
        // No-op on iOS - Health Connect privacy policy is Android only
        call.resolve()
    }

    @objc func queryWorkouts(_ call: CAPPluginCall) {
        let workoutType = call.getString("workoutType")
        let startDate = call.getString("startDate")
        let endDate = call.getString("endDate")
        let limit = call.getInt("limit")
        let ascending = call.getBool("ascending") ?? false
        let anchor = call.getString("anchor")

        implementation.queryWorkouts(
            workoutTypeString: workoutType,
            startDateString: startDate,
            endDateString: endDate,
            limit: limit,
            ascending: ascending,
            anchorString: anchor
        ) { result in
            DispatchQueue.main.async {
                switch result {
                case let .success(response):
                    call.resolve(response)
                case let .failure(error):
                    call.reject(error.localizedDescription, nil, error)
                }
            }
        }
    }

    @objc func queryAggregated(_ call: CAPPluginCall) {
        guard let dataType = call.getString("dataType") else {
            call.reject("dataType is required")
            return
        }

        let startDate = call.getString("startDate")
        let endDate = call.getString("endDate")
        let bucket = call.getString("bucket")
        let aggregation = call.getString("aggregation")

        implementation.queryAggregated(
            dataTypeIdentifier: dataType,
            startDateString: startDate,
            endDateString: endDate,
            bucketString: bucket,
            aggregationString: aggregation
        ) { result in
            DispatchQueue.main.async {
                switch result {
                case let .success(response):
                    call.resolve(response)
                case let .failure(error):
                    call.reject(error.localizedDescription, nil, error)
                }
            }
        }
    }

}
