//
//  RookSummaries.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 RookSummaries: NSObject {

  private let summariesManager: RookSummaryManager = RookSummaryManager()

  @objc public func getSleepSummaries(call: CAPPluginCall) {
    Task {
      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")
      }
      do {
        let summaries: [RookSleepSummary] = try await summariesManager.getSleepSummary(date: date)
        let mapper: SleepSummaryToDictionaryMapper = SleepSummaryToDictionaryMapper()
        let dictionaries: [[String: Any?]] = summaries.map({
          mapper.map($0)
        })
        call.resolve(["result" : dictionaries])
      } catch {
        call.reject(error.localizedDescription)
      }
    }
  }

  @objc public func getPhysicalSummary(call: CAPPluginCall) {
    Task {
      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")
      }
      do {
        let summary: RookPhysicalSummary = try await summariesManager.getPhysicalSummary(date: date)
        let mapper: PhysicalSummaryDictionaryMapper = PhysicalSummaryDictionaryMapper()
        let dictionary: [String: Any?] = mapper.map(summary)
        call.resolve(["result" : dictionary])
      } catch {
        call.reject(error.localizedDescription)
      }
    }
  }

  @objc public func getBodySummary(call: CAPPluginCall) {
    Task {
      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")
      }
      do {
        let summary: RookBodySummary = try await summariesManager.getBodySummary(date: date)
        let mapper: BodySummaryDictionaryMapper = BodySummaryDictionaryMapper()
        let dictionaries: [String: Any?] = mapper.map(summary)
        call.resolve(["result" : dictionaries])
      } catch {
        call.reject(error.localizedDescription)
      }
    }
  }

  @objc public func syncSummaries(call: CAPPluginCall) {
    summariesManager.sync { _ in
      call.resolve(["result" : true])
    }
  }

  @objc public func sync(call: CAPPluginCall) {
    let stringDate: String? = call.getString("date")
    let types: JSArray? = call.getArray("types")

    if shouldSyncAll(stringDate) {
      syncAll(call: call)
    } else if shouldSyncByDate(stringDate: stringDate, types: types) {
      syncByDate(stringDate: stringDate, call: call)
    } else {
      syncByDate(stringDate, types: types, call: call)
    }
  }

  private func syncAll(call: CAPPluginCall) {
    summariesManager.sync { _ in
      call.resolve(["result" : true])
    }
  }

  private func syncByDate(stringDate: String?, call: CAPPluginCall) {
    guard let date: Date = DateHelper().getDateFromString(stringDate: stringDate ?? "") else {
      return call.reject("incorrect date format should be yyyy-MM-dd")
    }
    summariesManager.sync(date) { result in
      switch result {
      case .success(let success):
        call.resolve(["result" : success])
      case .failure(let error):
        call.reject(error.localizedDescription)
      }
    }
  }

  private func syncByDate(_ stringDate: String?, types: JSArray?, call: CAPPluginCall) {
    guard let date: Date = DateHelper().getDateFromString(stringDate: stringDate ?? "") else {
      return call.reject("incorrect date format should be yyyy-MM-dd")
    }
    var uploadTypes: [SummaryTypeToUpload] = []
    if let types: JSArray = types {
      for type in types {
        if let stringValue: String = type as? String,
           let typeToUpload = SummaryTypeToUpload(rawValue: stringValue) {
          uploadTypes.append(typeToUpload)
        }
      }
    }
    summariesManager.sync(date, summaryType: uploadTypes) { result in
      switch result {
      case .success(let success):
        call.resolve(["result" : success])
      case .failure(let error):
        call.reject(error.localizedDescription)
      }
    }
  }

  private func shouldSyncByDate(stringDate: String?, types: JSArray?) -> Bool {
    guard let date: String = stringDate, !date.isEmpty else {
      return false
    }
    guard let types: JSArray = types else {
      return true
    }
    return types.isEmpty
  }

  private func shouldSyncAll(_ stringDate: String?) -> Bool {
    guard let date: String = stringDate, date.isEmpty else {
      return true
    }
    return false
  }

  @objc public func syncSleepSummary(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")
    }
    summariesManager.sync(date, summaryType: [.sleep]) { result in
      switch result {
      case .success(let success):
        call.resolve(["result" : success])
      case .failure(let error):
        call.reject(error.localizedDescription)
      }
    }
  }

  @objc public func syncPhysicalSummary(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")
    }
    summariesManager.sync(date, summaryType: [.physical]) { result in
      switch result {
      case .success(let success):
        call.resolve(["result" : success])
      case .failure(let error):
        call.reject(error.localizedDescription)
      }
    }
  }

  @objc public func syncBodySummary(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")
    }
    summariesManager.sync(date, summaryType: [.body]) { result in
      switch result {
      case .success(let success):
        call.resolve(["result" : success])
      case .failure(let error):
        call.reject(error.localizedDescription)
      }
    }
  }

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