import Foundation
import Capacitor
import RookSDK

/**
 * Please read the Capacitor iOS Plugin Development Guide
 * here: https://capacitorjs.com/docs/plugins/ios
 */
@objc(RookSDKPlugin)
public class RookSDKPlugin: CAPPlugin {

  private let configuration: RookConfiguration = RookConfiguration()
  private let permissions: RookPermissions = RookPermissions()
  private let backGround: RookBackGround = RookBackGround()
  private let syncSummaries: RookSummaries = RookSummaries()
  private let syncEvents: RookEvents = RookEvents()
  private let dataSource: RookDataSource = RookDataSource()
  private let userManager: RookUsersManager = RookUsersManager()

  // MARK: - Configuration

  @objc func initRook(_ call: CAPPluginCall) {
    let result = configuration.initRook(
      environment: call.getString("environment", "sandbox"),
      clientUUID: call.getString("clientUUID", ""),
      secret: call.getString("secret", ""),
      bundleId: call.getString("bundleId"),
      enableBackgroundSync: call.getBool("enableBackgroundSync") ?? false,
      enableEventsBackgroundSync: call.getBool("enableEventsBackgroundSync") ?? false,
      enableLogs: call.getBool("enableLogs") ?? false
    )
    call.resolve(["result": result])
  }

  @objc func getDiagnostic(_ call: CAPPluginCall) {
    configuration.getDiagnostic(call: call)
  }

  // MARK: User

  @objc func updateUserId(_ call: CAPPluginCall) {
    userManager.updateUserId(call: call)
  }

  @objc func getUserId(_ call: CAPPluginCall) {
    userManager.getUserId(call: call)
  }

  @objc func deleteUserFromRook(_ call: CAPPluginCall) {
    userManager.removeUserFromRook(call: call)
  }

  @objc func syncUserTimeZone(_ call: CAPPluginCall) {
    configuration.syncUserTimeZone(call: call)
  }

  @objc func enableAppleHealthSync(_ call: CAPPluginCall) {
    configuration.enableAppleHealthSync(call: call)
  }

  @objc func disableAppleHealthSync(_ call: CAPPluginCall) {
    configuration.disableAppleHealthSync(call: call)
  }

  @objc func isAppleHealthSyncEnable(_ call: CAPPluginCall) {
    let isEnable: Bool = configuration.isAppleHealthSyncEnable()
    call.resolve(["isEnable" : isEnable])
  }

  @objc func checkAvailability(_ call: CAPPluginCall) {
    call.resolve(["result": configuration.checkAvailability()])
  }

  // MARK: Permission

  @objc func requestAppleHealthPermissions(_ call: CAPPluginCall) {
    permissions.requestAppleHealthPermissions(call: call)
  }

  @objc func requestAllHealthConnectPermissions(_ call: CAPPluginCall) {
    permissions.requestAllHealthConnectPermissions(call: call)
  }

  @objc func openIOSAppleHealth(_ call: CAPPluginCall) {
    permissions.openIOSAppleHealth(call: call)
  }

  @objc func openHealthConnectSettings(_ call: CAPPluginCall) {
    permissions.openHealthConnectSettings(call: call)
  }

  @objc func healthConnectHasPermissions(_ call: CAPPluginCall) {
    permissions.healthConnectHasPermissions(call: call)
  }

  @objc func requestAndroidBackgroundPermissions(_ call: CAPPluginCall) {
    permissions.requestAndroidBackgroundPermissions(call: call)
  }

  @objc func requestDietaryWritePermissions(_ call: CAPPluginCall) {
    permissions.requestDietaryWritePermissions(call: call)
  }

  // MARK: Background

  @objc func enableBackGroundUpdates(_ call: CAPPluginCall) {
    backGround.enableBackGroundUpdates(call: call)
  }

  @objc func disableBackGroundUpdates(_ call: CAPPluginCall) {
    backGround.disableBackGroundUpdates(call: call)
  }
  
  @objc func isBackGroundUpdatesEnable(_ call: CAPPluginCall) {
    backGround.isBackGroundUpdatesEnable(call: call)
  }

  @objc func enableBackGroundEventsUpdates(_ call: CAPPluginCall) {
    backGround.enableBackGroundEventsUpdates(call: call)
  }

  @objc func disableBackGroundEventsUpdates(_ call: CAPPluginCall) {
    backGround.disableBackGroundEventsUpdates(call: call)
  }
  
  @objc func isBackGroundEventsUpdatesEnable(_ call: CAPPluginCall) {
    backGround.isBackGroundEventsUpdatesEnable(call: call)
  }

  // MARK: Manual Sync Summaries

  @objc func getSleepSummaries(_ call: CAPPluginCall) {
    syncSummaries.getSleepSummaries(call: call)
  }

  @objc func getPhysicalSummary(_ call: CAPPluginCall) {
    syncSummaries.getPhysicalSummary(call: call)
  }

  @objc func getBodySummary(_ call: CAPPluginCall) {
    syncSummaries.getBodySummary(call: call)
  }

  @objc public func sync(call: CAPPluginCall) {
    syncSummaries.sync(call: call)
  }

  @objc func shouldSyncFor(_ call: CAPPluginCall) {
    call.unimplemented("Not implemented on iOS.")
  }

  @objc func syncSummaries(_ call: CAPPluginCall) {
    syncSummaries.syncSummaries(call: call)
  }

  @objc public func syncSleepSummary(_ call: CAPPluginCall) {
    syncSummaries.syncSleepSummary(call: call)
  }

  @objc public func syncPhysicalSummary(_ call: CAPPluginCall) {
    syncSummaries.syncPhysicalSummary(call: call)
  }

  @objc public func syncBodySummary(_ call: CAPPluginCall) {
    syncSummaries.syncBodySummary(call: call)
  }

  @objc public func reSyncFailedSummaries(_ call: CAPPluginCall) {
    syncSummaries.reSyncFailedSummaries(call: call)
  }

  // MARK: Manual Sync Events

  @objc func syncEvents(_ call: CAPPluginCall) {
    syncEvents.syncEventsByType(call: call)
  }

  @objc func getActivityEvents(_ call: CAPPluginCall) {
    syncEvents.getActivityEvents(call: call)
  }

  @objc func writeNutritionEvent(_ call: CAPPluginCall) {
    syncEvents.writeNutritionEvent(call: call)
  }
  
  @objc func syncPendingEvents(_ call: CAPPluginCall) {
    syncEvents.syncPendingEvents(call: call)
  }

  @objc func getTodayStepCount(_ call: CAPPluginCall) {
    syncEvents.getTodayStepCount(call: call)
  }

  @objc func getTodayCalories(_ call: CAPPluginCall) {
    syncEvents.getTodayCalories(call: call)
  }

  @objc func getTodayHeartRate(_ call: CAPPluginCall) {
    syncEvents.getTodayHeartRate(call: call)
  }

  // MARK: Data sources

  @objc func getDataSourcesAuthorized(_ call: CAPPluginCall) {
    dataSource.getDataSourcesAuthorized(call: call)
  }

  @objc func getDataSourceAuthorizer(_ call: CAPPluginCall) {
    dataSource.getDataSourceAuthorizer(call: call)
  }

  @objc func revokeDataSource(_ call: CAPPluginCall) {
    dataSource.revokeDataSource(call: call)
  }

  // MARK: Listeners

  @objc func startListening(_ call: CAPPluginCall) {
    NotificationCenter.default.removeObserver(self)
    NotificationCenter.default.addObserver(
      self,
      selector: #selector(handleErrorListenerEvent),
      name: NSNotification.Name.init(EventNames.errorBackGround),
      object: nil)
    call.resolve(["result": true])
  }

  @objc func stopListening(_ call: CAPPluginCall) {
    NotificationCenter.default.removeObserver(self)
    call.resolve(["result": true])
  }
}

extension RookSDKPlugin {
  @objc fileprivate func handleErrorListenerEvent(_ notification: Notification) {
    guard let notificationInfo:  [AnyHashable : Any] = notification.userInfo,
          let error: Error = notificationInfo["Error"] as? Error else {
      return
    }
    self.notifyListeners("io.tryrook.background.appleHealth.errors", data: ["result": error.localizedDescription])
  }
}
