//
//  JedAIModule.swift
//  JedaiReactNativePackage
//
//  Copyright © 2022 Anagog Ltd. All rights reserved.
//

import Foundation
import React
import JedAIKit
import JedAIMetricsKit
import JedAIJEMAKit
import JedAIReportKit
import JedAIGeofenceKit
import JedAILambdaKit

@objc(JedAIModule)
class JedAIReactNativeBridge: NSObject {
    
    var bridge: AnagogBridgeAPI {
        return AnagogSDKWrapper.shared.bridgeAPI
    }
    
    // MARK: - Campaigns
    
    @objc
    func syncCampaigns(_ resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) {
        do {
            try self.bridge.downloadCampaigns()
            resolve(nil)
        } catch {
            reject(nil, error.localizedDescription, error)
        }
    }
    
    @objc
    func simulateCampaign(_ campaignIdentifier: String?, resolver resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) {
        do {
            try self.bridge.simulateCampaign(campaignIdentifier)
            resolve(nil)
        } catch {
            reject(nil, error.localizedDescription, error)
        }
    }
    
    @objc
    func getCampaigns(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
        self.bridge.getCampaigns { result in
            switch result {
            case .success(let campaigns):
                resolve(campaigns)
            case .failure(let error):
                reject(nil, error.localizedDescription, error)
            }
        }
    }
    
    
    // MARK: - Micromoments
    
    @objc
    func fireMicromoment(_ micromoment: Dictionary<String, Any>, resolver resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) {
        do {
            try self.bridge.fireMicromoment(micromoment)
            resolve(nil)
        } catch {
            os_log_file("Error during fire micromoment %@", error as NSError)
            reject(nil, error.localizedDescription, error)
        }
    }
    
    
    // MARK: - Miscrosegments
    
    @objc
    func getUserDefinedString(_ customName: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
        self.bridge.getUserDefinedString(customName) { result in
            switch result {
            case .success(let value):
                resolve(value)
            case .failure(let error):
                reject(nil, error.localizedDescription, error)
            }
        }
    }
    
    @objc
    func getUserDefinedInteger(_ customName: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
        self.bridge.getUserDefinedInteger(customName) { result in
            switch result {
            case .success(let value):
                resolve(value)
            case .failure(let error):
                reject(nil, error.localizedDescription, error)
            }
        }
    }
    
    @objc
    func getUserDefinedDecimal(_ customName: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
        self.bridge.getUserDefinedDecimal(customName) { result in
            switch result {
            case .success(let value):
                resolve(value)
            case .failure(let error):
                reject(nil, error.localizedDescription, error)
            }
        }
    }
    
    @objc
    func setUserDefinedString(_ customName: String, value: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
        self.bridge.setUserDefinedString(customName, value: value) { error in
            if let error {
                reject(nil, error.localizedDescription, error)
                return
            }
            resolve(nil)
        }
    }
    
    @objc
    func setUserDefinedInteger(_ customName: String, value: Int, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
        self.bridge.setUserDefinedInteger(customName, value: value) { error in
            if let error {
                reject(nil, error.localizedDescription, error)
                return
            }
            resolve(nil)
        }
    }
    
    @objc
    func setUserDefinedDecimal(_ customName: String, value: Double, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
        self.bridge.setUserDefinedDecimal(customName, value: value) { error in
            if let error {
                reject(nil, error.localizedDescription, error)
                return
            }
            resolve(nil)
        }
    }
    
    
    // MARK: - Reports
    
    @objc
    func forceScheduleReports(_ resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) {
        do {
            try self.bridge.forceScheduleReports()
            resolve(nil)
        } catch {
            reject(nil, error.localizedDescription, error)
        }
    }
    
    @objc
    func requestMicrosegmentsSnapshotReport(_ resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) {
        do {
            try self.bridge.requestMicrosegmentsSnapshotReport()
            resolve(nil)
        } catch {
            reject(nil, error.localizedDescription, error)
        }
    }
    
    @objc
    func requestEncodedEnrichmentReport(_ resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) {
        do {
            try self.bridge.requestEncodedEnrichmentReport()
            resolve(nil)
        } catch {
            reject(nil, error.localizedDescription, error)
        }
    }
  
    @objc
    func exportDataEnrichment(_ requestedMetrics: Array<String>?, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
        self.bridge.exportDataEnrichment(requestedMetrics: requestedMetrics) { result in
            switch result {
            case .success(let value):
                resolve(value)
            case .failure(let error):
                reject(nil, error.localizedDescription, error)
            }
        }
    }
    
    
    // MARK: - JedAI
    
    @objc
    func enableJedAI(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
        self.bridge.enableJedAI {
            resolve(nil)
        }
    }
    
    @objc
    func disableJedAI(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
        self.bridge.disableJedAI {
            resolve(nil)
        }
    }
    
    @objc
    func disableAndPurgeJedAI(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
        self.bridge.disableAndPurgeJedAI {
            resolve(nil)
        }
    }
    
    @objc
    func getJedAIStatus(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
        resolve(self.bridge.getJedAIStatus())
    }
    
    @objc
    func shareFeedback(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
        self.bridge.shareFeedback { error in
            if let error {
                reject(nil, error.localizedDescription, error)
            }
            else {
                resolve(nil)
            }
        }
    }
    
    @objc
    func generateFeedback(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
        self.bridge.generateFeedback { result in
            switch result {
            case .success(let path):
                resolve(path)
            case .failure(let error):
                reject(nil, error.localizedDescription, error)
            }
        }
    }
    
    @objc
    func getVersion(_ resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) {
        resolve(self.bridge.getVersion())
    }
    
    @objc
    func openDebuggingScreen(_ info: [String: Any], resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
        self.bridge.openDebuggingScreen(additionalInfo: info) { error in
            if let error = error {
                reject(nil, error.localizedDescription, error)
                return
            }
            
            resolve(nil)
        }
    }
    
    
    // MARK: - Onboarding
    
    @objc
    func onboardingStart(_ resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) {
        do {
            try self.bridge.onboardingStart()
            resolve(nil)
        } catch {
            reject(nil, error.localizedDescription, error)
        }
    }
    
    @objc
    func onboardingComplete(_ resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) {
        do {
            try self.bridge.onboardingComplete()
            resolve(nil)
        } catch {
            reject(nil, error.localizedDescription, error)
        }
    }
    
    @objc
    func onboardingMarkAsCompleted(_ resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) {
        do {
            try self.bridge.onboardingMarkAsCompleted()
            resolve(nil)
        } catch {
            reject(nil, error.localizedDescription, error)
        }
    }
    
    @objc
    func onboardingReset(_ resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) {
        do {
            try self.bridge.onboardingReset()
            resolve(nil)
        } catch {
            reject(nil, error.localizedDescription, error)
        }
    }
    
    
    // MARK: - PageTracker
    
    @objc
    func enterPage(_ pageName: String, resolver resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) {
        do {
            try self.bridge.enterPage(pageName)
            resolve(nil)
        } catch {
            reject(nil, error.localizedDescription, error)
        }
    }
    
    @objc
    func exitPage(_ resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) {
        do {
            try self.bridge.exitPage()
            resolve(nil)
        } catch {
            reject(nil, error.localizedDescription, error)
        }
    }
    
    
    // MARK: - Other
    
    @objc
    func sendUserInteractionEvent(_ campaignIdentifier: String, triggerType: String, resolver resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) {
        do {
            try self.bridge.sendUserInteractionEvent(campaignIdentifier: campaignIdentifier, triggerType: triggerType)
            resolve(nil)
        } catch {
            reject(nil, error.localizedDescription, error)
        }
    }
    
    @objc
    func streamIsReady() {
        EventEmitter.streamIsReady = true
        AnagogSDKWrapper.shared.eventEmitterManager.checkForSend()
    }
    
    @objc
    func handleUNUserNotificationCenter(_ resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) {
        self.bridge.handleUNUserNotificationCenter()
        resolve(nil)
    }
    
    
    // MARK: - Logs
    
    @objc
    func logInfo(_ message: String) {
        self.bridge.logInfo("[react-native] \(message)")
    }
    
    @objc
    func logError(_ message: String) {
        self.bridge.logError("[react-native] \(message)")
    }
    
    
    // MARK: - ReactNative methods
    
    @objc
    static func requiresMainQueueSetup() -> Bool {
        return true
    }
    
}
