//
//  NoPassRNBridgeAccountServiceiOS.swift
//  SdkTest
//
//  Created by Artsiom Shmaenkov on 1.07.21.
//

import Foundation
import NoPassSDKReact
import React

@objc(NoPassRNBridgeAccountServiceiOS)
public class NoPassRNBridgeAccountServiceiOS: NSObject, RCTBridgeModule {
    
    public static func moduleName() -> String! {
        return "NoPassRNBridgeAccountServiceiOS"
    }
    
    public static func requiresMainQueueSetup() -> Bool {
        return true
    }
    
    @objc public static var shared = NoPassRNBridgeAccountServiceiOS()
    
    private override init() {
        super.init()
        NoPassAccountService.shared.onAccountsChange = {
            EventEmitter.shared.dispatch(name: NoPassRNBridgeEvent.onAccountsWereChangedListener.rawValue,
                                         body: nil)
        }
    }
    
    @objc public func subscribeOnAccountsUpdates() {
        NoPassAccountService.shared.subscribe()
    }
    
    @objc public func fetchAccounts(_ resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock?) {
        let accounts = NoPassAccountService.shared.fetchAccounts()
        let jsonAccounts = accounts.map { $0.toDictionaryForRN() }
        resolver(jsonAccounts)
    }
    
    @objc public func fetchAccount(_ userCode: String, resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock?) {
        let account = NoPassAccountService.shared.fetchAccount(userCode: userCode)
        resolver(account?.toDictionaryForRN())
    }
    
    @objc public func fetchHistory(_ resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock?) {
        let histories = NoPassAccountService.shared.fetchHisory()
        let jsonHistories = histories.map{ $0.toDictionaryForRN() }
        resolver(jsonHistories)
    }
    
    @objc public func removeAccount(_ userCode: String, biometricType: String, isScreenLock: Bool, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
        DispatchQueue.main.async {
            guard let account = NoPassAccountService.shared.fetchAccount(userCode: userCode) else {
                rejecter("404", NoPassRNBridgeError.userNotFound.rawValue, nil)
                return
            }
            
            guard let type = BiometricType(rawValue: biometricType) else {
                rejecter("404", NoPassRNBridgeError.biometricTypeNotFound.rawValue, nil)
                return
            }
            
            NoPassAccountService.shared.removeAccount(account: account, enabled2FaMethod: type, isScreenLock: isScreenLock) { (error) in
                if let error = error {
                    rejecter(String((error as NSError).code), error.localizedDescription, error)
                } else {
                    resolver(true)
                }
            }
        }
    }
    
    @objc public func clearBackupData() {
        DispatchQueue.main.async {
            NoPassAccountService.shared.clearBackupData()
        }
    }
    
    @objc public func createEmptyBackupData(_ pin: String, resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock?) {
        let backupData = NoPassAccountService.shared.emptymptyBackupData(pin: pin)
        resolver(backupData)
    }
    
    @objc public func canDecodeBackupFile(_ encodedString: String, pin: String, resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock?) {
        let canDecode = NoPassAccountService.shared.isCanDecodeBackupFile(encodedString: encodedString, pin: pin)
        resolver(canDecode)
    }
    
    @objc public func backupAccounts(_ pin: String, encryptedBackupData: String?, biometricType: String, isScreenLock: Bool, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
        DispatchQueue.main.async {
            guard let type = BiometricType(rawValue: biometricType) else {
                rejecter("404", NoPassRNBridgeError.biometricTypeNotFound.rawValue, nil)
                return
            }
            
            NoPassAccountService.shared.backupAccounts(pin: pin, encryptedBackupData: encryptedBackupData, enabled2FaMethod: type, isSreenLock: isScreenLock) { (error, backupData) in
                if let error = error {
                    rejecter(String((error as NSError).code), error.errorDescription, error)
                } else {
                    resolver(backupData)
                }
            }
        }
    }
    
    @objc public func startRestoreDataFromBackup(_ backupData: String, pin: String, biometricType: String, isScreenLock: Bool, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
        DispatchQueue.main.async {
            guard let type = BiometricType(rawValue: biometricType) else {
                rejecter("404", NoPassRNBridgeError.biometricTypeNotFound.rawValue, nil)
                return
            }
            NoPassAccountService.shared.restoreAccounts(backupData: backupData, pin: pin, delegate: self, enabled2FaMethod: type, isScreenLock: isScreenLock) { (countOfAccounts, error) in
                if let error = error {
                    rejecter(String((error as NSError).code), error.errorDescription, error)
                } else {
                    resolver(["countOfAccountsForRestore" : countOfAccounts])
                }
            }
        }
    }
    
    func getDocumentsDirectory() -> URL {
        let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        return paths[0]
    }
}

extension NoPassRNBridgeAccountServiceiOS: RestoreFlowDelegate {
    public func restoreDidFinish(error: NopassError?) {
        EventEmitter.shared.dispatch(name: NoPassRNBridgeEvent.onAccountsRestoreDidFinishListener.rawValue,
                                     body: ["error" : error?.errorDescription])
    }
    
    public func accountDidRestore(account: NoPassAccount?) {
        EventEmitter.shared.dispatch(name: NoPassRNBridgeEvent.onAccountDidRestoreListener.rawValue,
                                     body: ["account" : account?.toDictionaryForRN()])
    }
}
