//
//  IziPayModule.swift
//
//  Created by Enrrique Antonio Pariasca Celiz on 10/06/25.
//

import Foundation
import IzipayPayButtonSDK
import VisaSensoryBranding
import MastercardSonic


@objc(IzipayModule)
class IzipayModule: NSObject {
  
  private let sonicManager: MCSonicController = MCSonicController()
  
  private var resolver: RCTPromiseResolveBlock?
  private var rejecter: RCTPromiseRejectBlock?
  
  /*
   PRIMERO SIEMPRE PROBAR EN SANDBOX (COORDINAR CON EL INTEGRADOR),
   ASEGURARSE QUE LAS IMAGENES DE SENSORING BRANDING FUNCIONEN CUANDO SE PRUEBE EN TESTFLIGHT
   APPLE PAY REQUIERE MAS PASOS QUE NO SE PUEDEN PONER EN ESTE EJEMPLO POR ESTAR RELACIONADO CON EL USO DE UNA CUENTA DE APPLE DEVELOPER,
   SEGUIR LA DOCUMENTACION DE APPLE E IZIPAY EN CASO DE QUERER ACTIVARLO
  */

  @objc(launchSdkActivity:
          action:publicKey:transactionId:merchantCode:
          facilitatorCode:orderNumber:currency:amount:
          payMethod:channel:processType:merchantBuyerId:dateTime:
          cardToken:
          firstName:lastName:email:phoneNumber:street:
          city:state:country:postalCode:documentType:
          document:language:
          isAmountLabelVisible:isLangControlVisible:showMessageResult:
          theme:payButtonBackgroundColor:textInputBorderColor:
          textInputPlaceholderTextColor:logo:urlIpn:presentationMode:
          promise:rejecter:)
  func launchSdkActivity(environment: String,
                         action: String,
                         publicKey: String,
                         transactionId: String,
                         merchantCode: String,
                         facilitatorCode: String,
                         orderNumber: String,
                         currency: String,
                         amount: String,
                         payMethod: String,
                         channel: String,
                         processType: String,
                         merchantBuyerId: String,
                         dateTime: String,
                         cardToken: String,
                         firstName: String,
                         lastName: String,
                         email: String,
                         phoneNumber: String,
                         street: String,
                         city: String,
                         state: String,
                         country: String,
                         postalCode: String,
                         documentType: String,
                         document: String,
                         language: String,
                         isAmountLabelVisible: Bool,
                         isLangControlVisible: Bool,
                         showMessageResult: Bool,
                         theme: String,
                         payButtonBackgroundColor: String,
                         textInputBorderColor: String,
                         textInputPlaceholderTextColor: String,
                         logo: String,
                         urlIpn: String,
                         presentationMode: String,
                         promise: @escaping RCTPromiseResolveBlock,
                         rejecter: @escaping RCTPromiseRejectBlock) -> Void{
    
    self.resolver = promise
    self.rejecter = rejecter
    
    print(transactionId)
    DispatchQueue.main.async {
      if let root = UIApplication.shared.delegate {
        var config = ConfigPaymentIzipay()
        config.enviroment = environment
        config.merchantCode = merchantCode
        config.facilitatorCode = facilitatorCode
        config.publicKey = publicKey
        
        config.transactionId = transactionId
        config.action = action
        
        config.order = OrderPaymentIzipay()
        config.order?.orderNumber = orderNumber
        config.order?.amount = amount
        config.order?.currency = currency
        config.order?.processType = processType
        config.order?.payMethod = self.paymentMethodsFromString(pm: payMethod) //[.card,.yape_code] //.apple_pay
        config.order?.merchantBuyerId = merchantBuyerId
        config.order?.dateTimeTransaction = dateTime
        //...
        config.billing = BillingPaymentIzipay()
        config.billing?.firstName = firstName
        config.billing?.lastName = lastName
        config.billing?.email = email
        config.billing?.phoneNumber = "989339999"
        config.billing?.street = "calle el demo sdk"
        config.billing?.city = "lima"
        config.billing?.state = "lima"
        config.billing?.country = "PE"
        config.billing?.postalCode = "00001"
        config.billing?.documentType = documentType
        config.billing?.document = document
        //...
        config.shipping = ShippingPaymentIzipay()
        config.shipping?.firstName = "Julio"
        config.shipping?.lastName = "Paredes"
        config.shipping?.email = "demo@izipay.pe"
        config.shipping?.phoneNumber = "989339999"
        config.shipping?.street = "calle el demo sdk"
        config.shipping?.city = "lima"
        config.shipping?.state = "lima"
        config.shipping?.country = "PE"
        config.shipping?.postalCode = "00001"
        config.shipping?.documentType = "DNI"
        config.shipping?.document = "12345678"
        
        config.token = TokenPaymentIzipay()
        config.token?.cardToken = cardToken
        
        config.appearance = AppearencePaymentIzipay()
        config.appearance?.theme = theme
        config.appearance?.logo = logo
        config.appearance?.formControls = AppearenceControlsPaymentIzipay()
        config.appearance?.formControls?.isAmountLabelVisible = isAmountLabelVisible
        config.appearance?.formControls?.isLangControlVisible = isLangControlVisible
        config.appearance?.language = language
        config.appearance?.customTheme = CustomThemePaymentIzipay()
        config.appearance?.visualSettings = AppearenceVisualSettingsPaymentIzipay()
        config.appearance?.visualSettings?.presentationMode = .fullscreen
        config.appearance?.visualSettings?.showResultScreen = showMessageResult
        
        //Objetos para sensory branding
        let sensoryBrandingVisa = SensoryBranding()
        sensoryBrandingVisa.backdropColor = .white
        sensoryBrandingVisa.isSoundEnabled = true
        sensoryBrandingVisa.isHapticFeedbackEnabled = true
        sensoryBrandingVisa.checkmarkMode = .checkmark

        let sensoryBrandMastercard = MCSonicView()
        sensoryBrandMastercard.background = MCSonicBackground.white

        config.appearance?.sensoryBrand = AppearenceSensoryBrandIzipay()
        config.appearance?.sensoryBrand?.visaSBView = sensoryBrandingVisa
        config.appearance?.sensoryBrand?.mastercardSBView = sensoryBrandMastercard

        print("modo presentacion: \(presentationMode)")
        
        self.showIzipayPaymentResult(configPayment: config, izipayPresentationMode: presentationMode, root: (root.window??.rootViewController)!)
      }
    }
  }
  
  func showIzipayPaymentResult(configPayment: ConfigPaymentIzipay, izipayPresentationMode: String, root : UIViewController) {
    if izipayPresentationMode == "FULLSCREEN" {
      var editableConfigPayment = configPayment
      editableConfigPayment.appearance?.visualSettings?.presentationMode = .fullscreen
      
      let s = UIStoryboard(name: "IziPayment", bundle: Bundle(for: PaymentFormViewController.self))
      let vc = s.instantiateViewController(withIdentifier: "PaymentFormView") as! PaymentFormViewController
      vc.delegate = self
      vc.configPayment = editableConfigPayment
      vc.modalPresentationStyle = .fullScreen
      root.present(vc, animated: true, completion: nil)
      
    } else {
      //No recomendado para hibrido por la complejidad, pero se deja por si se desea experiementar
      var editableConfigPayment = configPayment
      editableConfigPayment.appearance?.visualSettings?.presentationMode = .fullscreen
      
      let s = UIStoryboard(name: "ForEmbedStoryboard", bundle: Bundle(for: ForEmbedVC.self))
      let nvc = s.instantiateViewController(withIdentifier: "navigationContainerForEmbed") as! UINavigationController
      
      if #available(iOS 13.0, *) {
          let appearance = UINavigationBarAppearance()
          appearance.configureWithOpaqueBackground()
          appearance.backgroundColor = UIColor(red: 0.969, green: 0.969, blue: 0.969, alpha: 1.0)
          appearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor:UIColor.black]
          
          nvc.navigationBar.standardAppearance = appearance;
          nvc.navigationBar.scrollEdgeAppearance = nvc.navigationBar.standardAppearance

      } else {
          nvc.navigationBar.barTintColor = UIColor(red: 0.969, green: 0.969, blue: 0.969, alpha: 1.0)
          nvc.navigationBar.tintColor = .black
      }
      
      
      if let firstVC = nvc.viewControllers.first as? ForEmbedVC {
          //firstVC.delegate = self
          firstVC.configIzipay = editableConfigPayment
          firstVC.delegate = self
      }
      nvc.modalPresentationStyle = .fullScreen
      root.present(nvc, animated:true, completion: nil)
    }
  }
}

extension IzipayModule : IzipayPaymentDelegate {
  func getPaymentResult(_ paymentResult: IzipayPayButtonSDK.PaymentResult) {
    //Lectura de respuesta del SDK
    print(paymentResult.code ?? "")
    print(paymentResult.message ?? "")
    
    if let paymentResultCode = paymentResult.code {
      if paymentResultCode == "00" { //00 codigo operacion autorizada - Revisar listado de codigos de respuesta
        //puede validar los demas valores para garantizar la integridad de los datos
        self.resolver?((paymentResult.code ?? "nilCode")+"-"+(paymentResult.message ?? "nilMessage")+"- Revisar la clase IzipayModule en la carpeta ios de su proyecto React para recuperar los datos de la respuesta segun ajuste su desarrollo :"+(paymentResult.description))
        if let safeResponse = paymentResult.response {
          //puede validar los demas valores para garantizar la integridad de los datos o simplemente leerlos
        } else {
          //Si el codigo fue 00 pero el objeto response es nulo, consultar/anular orden
          self.rejecter?((paymentResult.code ?? "nilCode")+"-"+(paymentResult.message ?? "nilMessage"),"Pago denegado - otros",nil)
        }
      } else {
        //La operacion no se completo o fue rechazada consultar/anular orden
        self.rejecter?((paymentResult.code ?? "nilCode")+"-"+(paymentResult.message ?? "nilMessage"),"Pago denegado - otros",nil)
      }
    } else {
      //Si no hay un codigo de error, consultar/anular orden
      self.rejecter?((paymentResult.code ?? "nilCode")+"-"+(paymentResult.message ?? "nilMessage"),"Error - otros",nil)
    }
  }
  
  func executeProfiling(_ params: IzipayPayButtonSDK.ScoringParams) {
    
  }
  
  func paymentMethodsFromString(pm : String) -> [PaymentMethodIzipay]? {
    var paymentMethods : [PaymentMethodIzipay]?
    
    let metodosString :[String] = pm.split(separator: ",").map(String.init)
    let isAll = metodosString.contains(where: { $0 == "all" })
    
    if isAll {
        paymentMethods = [.all] //existe, pero no se muestra en el lado de react, solo habria q ver como activarlo
    } else {
      var selectedMethods: [PaymentMethodIzipay] = []

      if metodosString.contains("Tarjeta") {
          selectedMethods.append(.card)
      }

      if metodosString.contains("ApplePay") { //revisar los pasos de una integracion nativa en iOS y como activar apple pay
          selectedMethods.append(.apple_pay)
      }

      if metodosString.contains("Yape") {
          selectedMethods.append(.yape_code)
      }

      paymentMethods = selectedMethods
    }
    return paymentMethods
  }
  
  func executeSensoryBrandVisa(view: UIView) {
    if let visaview = view as? SensoryBranding {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
            visaview.animate()
        }
    }
  }
  
  func executeSensoryBrandMastercard(view: UIView, params: IzipayPayButtonSDK.MastercardSonicParams) {
    let merchant = MCSonicMerchant(merchantName: params.name, countryCode: params.country,
                                   city: nil, merchantCategoryCodes: [params.mcc], merchantId: nil)
    
    if let mastercardview = view as? MCSonicView, let safeMerchant = merchant {
        self.sonicManager.prepare(with: .soundAndAnimation, sonicCue: params.sonicCue,
                                  sonicEnvironment: .sandbox, merchant: safeMerchant) { status in
            
            if status == .success {
                self.sonicManager.play(with: mastercardview) { MCSonicStatus in
                    print(MCSonicStatus)
                }
            }
        }
        
    }
  }
}

extension IzipayModule : ForEmbedVCDelegate {
    func passResponseToOrigin(_ paymentResult: PaymentResult) {
        self.getPaymentResult(paymentResult)
    }
}
