import FawryPaySDK
import UIKit
import Foundation

@objc(RnFawryPaySdk)
class RnFawryPaySdk: RCTEventEmitter {
    
    static let FAWRY_EVENT_EMITTER_NAME = "RnFawryPaySdk"
    static let FAWRY_EVENT_PAYMENT_COMPLETED = "FAWRY_EVENT_PAYMENT_COMPLETED"
    static let FAWRY_EVENT_ON_SUCCESS = "FAWRY_EVENT_ON_SUCCESS"
    static let FAWRY_EVENT_ON_FAIL = "FAWRY_EVENT_ON_FAIL"
    static let FAWRY_EVENT_CardManager_FAIL = "FAWRY_EVENT_CardManager_FAIL"
    
    @objc
    func openCardsManager(
        _ baseUrl: String,
        lang: String,
        merchantInfo: NSDictionary,
        customerInfo: NSDictionary
    ) -> Void {
        DispatchQueue.main.async {
            
            let customerInfo = self.getCustomerInfo(customerInfo: customerInfo)
            
            let merchantInfo = self.getMerchantInfo(merchantInfo: merchantInfo)
            let launchModel = FawryLaunchModel(customer: customerInfo,
                                               merchant: merchantInfo,
                                               chargeItems: nil,
                                               signature: nil)
            
            FrameworkHelper.shared?.launchCardManager(
                on: self.getPresentedViewController()!,
                launchModel: launchModel,
                baseURL: baseUrl,
                appLanguage: self.getSelectedLanguage(lang: lang),
                currency: Currency.egp,
                enable3Ds: false,
                errorBlock: { error in
                    self.sendEvent(withName: RnFawryPaySdk.FAWRY_EVENT_CardManager_FAIL, body: error?.toJSON())
                }, onAddedNewCard: { card in
                    
                }, dismissBlock: {
                    self.sendEvent(withName: RnFawryPaySdk.FAWRY_EVENT_CardManager_FAIL, body: NSString(string: "User dismissed card manager"))
                  
                })
        }
    }
    
    @objc
    func startPayment(
        _ baseUrl: String,
        lang: String,
        merchantInfo: NSDictionary,
        customerInfo: NSDictionary,
        items: [NSDictionary],
        allow3DPayment: NSNumber ,
        skipReceipt:NSNumber ,
        skipLogin:NSNumber,
        payWithCardToken:NSNumber ,
        authCaptureMode:NSNumber ,
        allowVoucher:NSNumber ,
        signature: String?
    ) -> Void {
        let customerInfoAfterParse = self.getCustomerInfo(customerInfo: customerInfo)
        let merchantInfoAfterParse = self.getMerchantInfo(merchantInfo: merchantInfo)
        let itemsAfterParse = self.getItems(items: items)
        var parsedSignature: String? = nil
        if let unwrappedSignature = signature, !unwrappedSignature.isEmpty {
            parsedSignature = unwrappedSignature
        }
        let launchModel = FawryLaunchModel(customer: customerInfoAfterParse,
                                           merchant: merchantInfoAfterParse,
                                           chargeItems: itemsAfterParse,
                                           signature: parsedSignature,
                                           allowVoucher: allowVoucher.boolValue,
                                           paymentWithCardToken: payWithCardToken.boolValue,
                                           paymentMethod: .all)
        launchModel.skipCustomerInput = skipLogin.boolValue
        launchModel.skipReceipt = skipReceipt.boolValue
        let currentViewConroller = self.getPresentedViewController()!
        let selectedLangAfterParsing = self.getSelectedLanguage(lang: lang)
        
        
        DispatchQueue.main.async {
            FrameworkHelper.shared?.launchAnonymousSDK(on: currentViewConroller,
                                                       launchModel: launchModel,
                                                       baseURL: baseUrl,
                                                       appLanguage:selectedLangAfterParsing,
                                                       enable3Ds: allow3DPayment.boolValue,
                                                       authCaptureModePayment: authCaptureMode.boolValue,
                                                       completionBlock: { (status) in
            }, onPreCompletionHandler: { (error) in
            }, errorBlock: { (error) in
                self.sendEvent(withName: RnFawryPaySdk.FAWRY_EVENT_ON_FAIL, body: error?.toJSON())
            }, onPaymentCompletedHandler: { (chargeResponse) in
                if let response = chargeResponse as? PaymentChargeResponse{
                    self.sendEvent(withName: RnFawryPaySdk.FAWRY_EVENT_PAYMENT_COMPLETED, body: response.toJSON())
                }
                if let er = chargeResponse as? FawryError{
                    self.sendEvent(withName: RnFawryPaySdk.FAWRY_EVENT_PAYMENT_COMPLETED, body: er.toJSON())
                }
            }, onSuccessHandler: { (response) in
                if let response = response as? PaymentChargeResponse{
                    self.sendEvent(withName: RnFawryPaySdk.FAWRY_EVENT_ON_SUCCESS, body: response.toJSON())
                }
            })
        }
    }
    
    func getCustomerInfo(customerInfo:NSDictionary) -> LaunchCustomerModel {
        let result = LaunchCustomerModel(
            customerName: (customerInfo.value(forKey: "customerName") as? String?) ?? "" ,
            customerEmail: (customerInfo.value(forKey: "customerEmail") as? String?) ?? "",
            customerMobile: (customerInfo.value(forKey: "customerMobile") as? String?) ?? "",
            customerProfileId: (customerInfo.value(forKey: "customerProfileId") as? String?) ?? ""
        )
        return result
    }
    
    func getMerchantInfo(merchantInfo:NSDictionary) -> LaunchMerchantModel {
        let result = LaunchMerchantModel(
            merchantCode: (merchantInfo.value(forKey: "merchantCode") as? String?) ?? "",
            merchantRefNum: (merchantInfo.value(forKey: "merchantRefNum") as? String?) ?? "",
            secureKey: (merchantInfo.value(forKey: "merchantSecretCode") as? String?) ?? ""
        )
        return result
    }
    
    func getItems(items:[NSDictionary]) -> [ChargeItemsParamsModel] {
        var result: [ChargeItemsParamsModel] = []
        for item in items {
            result.append(
                ChargeItemsParamsModel(
                    itemId: (item.object(forKey: "itemId") as! String),
                    charge_description: (item.object(forKey: "description") as? String?) ?? "",
                    price: (Double(item.object(forKey: "price") as? String ?? "0.0") ?? 0.0),
                    quantity: (Int(item.object(forKey: "quantity") as? String ?? "0") ?? 0)
                )
            )
        }
        return result
    }
    
    func getSelectedLanguage(lang:String) -> String
    {
        if lang == "ARABIC" {
            return AppLanguage.Arabic
        }
        else{
            return AppLanguage.English
            
        }
    }
    
    func getPresentedViewController() -> UIViewController?
    {
        let presentedViewController = RCTPresentedViewController()
        let topController = UIApplication.shared.topMostViewController()
        return presentedViewController ?? topController
    }
    
    override func supportedEvents() -> [String]! {
        return [RnFawryPaySdk.FAWRY_EVENT_PAYMENT_COMPLETED,RnFawryPaySdk.FAWRY_EVENT_ON_SUCCESS,RnFawryPaySdk.FAWRY_EVENT_ON_FAIL,RnFawryPaySdk.FAWRY_EVENT_CardManager_FAIL]
    }
    
    static override func requiresMainQueueSetup() -> Bool{
        return true;
    }
}

extension UIViewController {
    func topMostViewController() -> UIViewController {
        if self.presentedViewController == nil {
            return self
        }
        if let navigation = self.presentedViewController as? UINavigationController {
            return navigation.visibleViewController!.topMostViewController()
        }
        if let tab = self.presentedViewController as? UITabBarController {
            if let selectedTab = tab.selectedViewController {
                return selectedTab.topMostViewController()
            }
            return tab.topMostViewController()
        }
        return self.presentedViewController!.topMostViewController()
    }
}
extension UIApplication {
    func topMostViewController() -> UIViewController? {
        return UIWindow.key!.rootViewController?.topMostViewController()
    }
}
extension UIWindow {
    static var key: UIWindow? {
        if #available(iOS 13, *) {
            return UIApplication.shared.windows.first { $0.isKeyWindow }
        } else {
            return UIApplication.shared.keyWindow
        }
    }
}

extension Encodable {
    func toJSON(_ encoder: JSONEncoder = JSONEncoder()) -> NSString {
        guard let data = try? encoder.encode(self) else { return NSString(string: "") }
        let result = String(decoding: data, as: UTF8.self)
        return NSString(string: result)
    }
}
