//
//  RookEvents.swift
//  Plugin
//
//  Created by Francisco Guerrero Escamilla on 04/05/24.
//  Copyright © 2024 Max Lynch. All rights reserved.
//

import Foundation
import RookSDK
import Capacitor

@objc public class RookEvents: NSObject {

  private let eventsManager: RookEventsManager = RookEventsManager()

  @objc public func syncEvents(call: CAPPluginCall) {
    eventsManager.syncEvents {
      call.resolve(["result" : true])
    }
  }

  @objc public func syncEventsByType(call: CAPPluginCall) {
    let stringDate: String = call.getString("date", "")
    let eventTypeString: String = call.getString("type", "")
    guard let date: Date = DateHelper().getDateFromString(stringDate: stringDate) else {
      return call.reject("incorrect date format should be yyyy-MM-dd")
    }
    guard let eventType: EventTypeToUpload = EventTypeToUpload(rawValue: eventTypeString) else {
      return call.reject("incorrect event type")
    }
    eventsManager.syncEvents(date: date, eventType: eventType) { result in
      switch result {
      case .success(let success):
        call.resolve(["result" : success])
      case .failure(let error):
        call.reject(error.localizedDescription)
      }
    }
  }

  @objc public func getActivityEvents(call: CAPPluginCall) {
    Task {
      let stringDate: String = call.getString("date", "")
      let mapper: ActivityEventMapper = ActivityEventMapper()
      guard let date: Date = DateHelper().getDateFromString(stringDate: stringDate) else {
        return call.reject("incorrect date format should be yyyy-MM-dd")
      }
      do {
        let events: [RookActivityEvent] = try await  eventsManager.getActivityEvents(date: date)
        let jsonEvents: [[String: Any?]] = events.map({
          mapper.map(event: $0)
        })
        call.resolve(["result" : jsonEvents])
      } catch {
        call.reject(error.localizedDescription)
      }
    }
  }

  @objc public func syncBodyHeartRateEvent(call: CAPPluginCall) {
    let stringDate: String = call.getString("date", "")
    guard let date: Date = DateHelper().getDateFromString(stringDate: stringDate) else {
      return call.reject("incorrect date format should be yyyy-MM-dd")
    }
    eventsManager.syncEvents(date: date, eventType: .heartRate) { result in
      switch result {
      case .success(let success):
        call.resolve(["result" : success])
      case .failure(let error):
        call.reject(error.localizedDescription)
      }
    }
  }

  @objc public func syncPhysicalHeartRateEvent(call: CAPPluginCall) {
    let stringDate: String = call.getString("date", "")
    guard let date: Date = DateHelper().getDateFromString(stringDate: stringDate) else {
      return call.reject("incorrect date format should be yyyy-MM-dd")
    }
    eventsManager.syncEvents(date: date, eventType: .heartRate) { result in
      switch result {
      case .success(let success):
        call.resolve(["result" : success])
      case .failure(let error):
        call.reject(error.localizedDescription)
      }
    }
  }

  @objc public func syncBodyOxygenationEvent(call: CAPPluginCall) {
    let stringDate: String = call.getString("date", "")
    guard let date: Date = DateHelper().getDateFromString(stringDate: stringDate) else {
      return call.reject("incorrect date format should be yyyy-MM-dd")
    }
    eventsManager.syncEvents(date: date, eventType: .oxygenation) { result in
      switch result {
      case .success(let success):
        call.resolve(["result" : success])
      case .failure(let error):
        call.reject(error.localizedDescription)
      }
    }
  }

  @objc public func syncPhysicalOxygenationEvent(call: CAPPluginCall) {
    let stringDate: String = call.getString("date", "")
    guard let date: Date = DateHelper().getDateFromString(stringDate: stringDate) else {
      return call.reject("incorrect date format should be yyyy-MM-dd")
    }
    eventsManager.syncEvents(date: date, eventType: .oxygenation) { result in
      switch result {
      case .success(let success):
        call.resolve(["result" : success])
      case .failure(let error):
        call.reject(error.localizedDescription)
      }
    }
  }

  @objc public func syncTrainingEvent(call: CAPPluginCall) {
    let stringDate: String = call.getString("date", "")
    guard let date: Date = DateHelper().getDateFromString(stringDate: stringDate) else {
      return call.reject("incorrect date format should be yyyy-MM-dd")
    }
    eventsManager.syncEvents(date: date, eventType: .activityEvent) { result in
      switch result {
      case .success(let success):
        call.resolve(["result" : success])
      case .failure(let error):
        call.reject(error.localizedDescription)
      }
    }
  }

  @objc public func syncTemperatureEvents(call: CAPPluginCall) {
    let stringDate: String = call.getString("date", "")
    guard let date: Date = DateHelper().getDateFromString(stringDate: stringDate) else {
      return call.reject("incorrect date format should be yyyy-MM-dd")
    }
    eventsManager.syncEvents(date: date, eventType: .temperature) { result in
      switch result {
      case .success(let success):
        call.resolve(["result" : success])
      case .failure(let error):
        call.reject(error.localizedDescription)
      }
    }
  }

  @objc public func syncBloodPressureEvents(call: CAPPluginCall) {
    let stringDate: String = call.getString("date", "")
    guard let date: Date = DateHelper().getDateFromString(stringDate: stringDate) else {
      return call.reject("incorrect date format should be yyyy-MM-dd")
    }
    eventsManager.syncEvents(date: date, eventType: .bloodPressure) { result in
      switch result {
      case .success(let success):
        call.resolve(["result" : success])
      case .failure(let error):
        call.reject(error.localizedDescription)
      }
    }
  }

  @objc public func syncBloodGlucoseEvents(call: CAPPluginCall) {
    let stringDate: String = call.getString("date", "")
    guard let date: Date = DateHelper().getDateFromString(stringDate: stringDate) else {
      return call.reject("incorrect date format should be yyyy-MM-dd")
    }
    eventsManager.syncEvents(date: date, eventType: .bloodGlucose) { result in
      switch result {
      case .success(let success):
        call.resolve(["result" : success])
      case .failure(let error):
        call.reject(error.localizedDescription)
      }
    }
  }

  @objc public func syncBodyMetricsEvents(call: CAPPluginCall) {
    let stringDate: String = call.getString("date", "")
    guard let date: Date = DateHelper().getDateFromString(stringDate: stringDate) else {
      return call.reject("incorrect date format should be yyyy-MM-dd")
    }
    eventsManager.syncEvents(date: date, eventType: .bodyMetrics) { result in
      switch result {
      case .success(let success):
        call.resolve(["result" : success])
      case .failure(let error):
        call.reject(error.localizedDescription)
      }
    }
  }

  @objc public func syncPendingEvents(call: CAPPluginCall) {
    eventsManager.syncPendingEvents { result in
      switch result {
      case .success(let success):
        call.resolve(["result" : success])
      case .failure(let error):
        call.reject(error.localizedDescription)
      }
    }
  }

  @objc public func getTodayStepCount(call: CAPPluginCall) {
    eventsManager.getTodayStepCount { result in
      switch result {
      case .success(let count):
        call.resolve(["stepCount" : count])
      case .failure(let error):
        call.reject(error.localizedDescription)
      }
    }
  }

  @objc public func getTodayCalories(call: CAPPluginCall) {
    eventsManager.getTodayCalories { result in
      switch result {
      case .success(let calories):
        call.resolve(["basal" : calories.basalCalories ?? .zero,
                      "active": calories.activeCalories ?? .zero])
      case .failure(let error):
        call.reject(error.localizedDescription)
      }
    }
  }

  @objc public func getTodayHeartRate(call: CAPPluginCall) {
    eventsManager.getTodayHeartRate() { result in
      switch result {
      case .success(let heartRateData):
        let mapper: HeartRateMapper = HeartRateMapper()
        let data: [String: Any?] = mapper.map(heartRateData)
        call.resolve(["result" : data])
      case .failure(let error):
        call.reject(error.localizedDescription)
      }
    }
  }

  @objc public func writeNutritionEvent(call: CAPPluginCall) {
    guard let eventDictionary: JSObject = call.getObject("event") else {
      return call.reject("missing event")
    }
    do {
      let data: Data = try JSONSerialization.data(withJSONObject: eventDictionary, options: [])
      let decoder: JSONDecoder = JSONDecoder()
      let dto: NutritionInsertionEventDTO = try decoder.decode(NutritionInsertionEventDTO.self, from: data)
      let eventRookDomain: NutritionInsertionEvent = try NutritionInsertionEventDTOMapper().toDomain(event: dto)
      eventsManager.writeNutritionEvent(event: eventRookDomain) { result in
        switch result {
        case .success(let success):
          call.resolve(["result" : data])
        case .failure(let error):
          call.reject(error.localizedDescription)
        }
      }
    } catch {
      call.reject(error.localizedDescription)
    }
  }
}
