//
//  ViewController.swift
//  ExampleIzipaySDK
//
//  Created by Desarrollo on 4/10/23.
//

import UIKit

/**
 * Integración con iOS - Paso 3
 * https://developers.izipay.pe/ios-core/integration-with-ios/#paso-3-configuraci%C3%B3n-en-el-controlador-de-la-pantalla
 * Actualizado al 27-08-2025
 */
import IzipayPayButtonSDK

/**
 * Integración con iOS - Cybersource - Paso 2
 * https://developers.izipay.pe/ios-core/integration-with-cybersource/#paso-2
 */
import RLTMXProfiling
import RLTMXProfilingConnections
/**
 * Integración con iOS - Paso 7
 * https://developers.izipay.pe/ios-core/integration-with-ios/#paso-7-integraci%C3%B3n-con-librer%C3%ADas-de-sensory-branding
 */
import VisaSensoryBranding
import MastercardSonic


class MainViewController: UIViewController {
    
    @IBOutlet weak var txtvResult: UITextView!
    @IBOutlet weak var swtModalidad: UISwitch!
    @IBOutlet weak var txtCodComercio: UITextField!
    @IBOutlet weak var txtLlavePublica: UITextField!
    
    var transactionId : String?
    
    /**
     * Integración con iOS - Cybersource - Paso 3
     * https://developers.izipay.pe/ios-core/integration-with-cybersource/#paso-3
     */
    var profile : RLTMXProfiling? = RLTMXProfiling.sharedInstance() //requerido para la deteccion de fraude de cybersource, solo si el comercio lo ha pedido


    /**
     * Integración con iOS - Paso 7
     */
    private let sonicManager: MCSonicController = MCSonicController()
    
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        print("IZIPAY SDK version: \(IzipaySDKUtils.sdkVersion())")
    }

    @IBAction func onTapPay(_ sender: Any) {
        let configIzipay = initializeConfigPayment()
        self.showIzipayPaymentResult(configPayment: configIzipay)
    }
    
    func showIzipayPaymentResult(configPayment: ConfigPaymentIzipay) {
        /**
         * Integración con iOS - Modos de visualización
         * https://developers.izipay.pe/ios-core/integration-with-ios/#modos-de-visualizaci%C3%B3n
         * Actualizado al 27-08-2025
         */
        if let presentationMode = configPayment.appearance?.visualSettings?.presentationMode {
            switch presentationMode {
            case .embedded:
                //Este es un ejemplo varia de acuerdo a la forma en que desee manejar el modo embebido
                let s = UIStoryboard(name: "Main", 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.configIzipay = configPayment
                    firstVC.delegate = self
                }
                nvc.modalPresentationStyle = .fullScreen
                self.present(nvc, animated:true, completion: nil)

            case .fullscreen:
                let s = UIStoryboard(name: "IziPayment", bundle: Bundle(for: PaymentFormViewController.self))
                let vc = s.instantiateViewController(withIdentifier: "PaymentFormView") as! PaymentFormViewController
                vc.delegate = self
                vc.configPayment = configPayment
                vc.modalPresentationStyle = .fullScreen
                self.present(vc, animated: true, completion: nil)
            default:
                print("modo de presentacion invalido")
            }
        }
    }
    
    /**
     * Integración con iOS - Paso 3
     * https://developers.izipay.pe/ios-core/integration-with-ios/#paso-4-crear-el-objeto-de-configuraci%C3%B3n
     * Actualizado al 27-08-2025
     */
    func initializeConfigPayment() -> ConfigPaymentIzipay {
        //Siempre inicializar los objetos antes de pasarle valores
        let random = Int.random(in: 356547157..<366547157) //solo es un ejemplo, el transactionId debe ser unico y el comercio elige la forma de generarlo
        
        let tranxId = "\(random)"
        self.transactionId = tranxId
        
        var config = ConfigPaymentIzipay()
        config.enviroment = "SBOX" //TEST o PROD o SBOX
        config.merchantCode = txtCodComercio.text//"4001834"
        config.facilitatorCode = ""
        config.publicKey = "VErethUtraQuxas57wuMuquprADrAHAb"
        
        config.transactionId = tranxId
        config.action = "pay_register"
        
        config.order = OrderPaymentIzipay()
        config.order?.orderNumber = "10\(random)"
        config.order?.amount = "10.54"
        config.order?.currency = "PEN"
        //config.order?.channel = "mobile" ya no requerido
        config.order?.processType = "autorize" //"autorize" o "preautorize"
        config.order?.payMethod = [.all] //card, apple_pay, yape_code, all
        config.order?.merchantBuyerId = "MB10\(random)" //es un ejemplo, debe ser unico por usuario del comercio
        config.order?.dateTimeTransaction = "\(currentTimeMillis())"
        
        config.billing = BillingPaymentIzipay()
        config.billing?.firstName = "Juan"
        config.billing?.lastName = "Wick Quispe"
        config.billing?.email = "demosdk@izipay.pe"
        config.billing?.phoneNumber = "989339999"
        config.billing?.street = "calle el demo sdk example"
        config.billing?.city = "lima"
        config.billing?.state = "lima"
        config.billing?.country = "PE"
        config.billing?.postalCode = "15047"
        config.billing?.documentType = "DNI"
        config.billing?.document = "22334455"
        
        config.shipping = ShippingPaymentIzipay()
        config.shipping?.firstName = "Enrrique"
        config.shipping?.lastName = "Pariasca"
        config.shipping?.email = "demosdk@izipay.pe"
        config.shipping?.phoneNumber = "989339999"
        config.shipping?.street = "calle el demo sdk example"
        config.shipping?.city = "lima"
        config.shipping?.state = "lima"
        config.shipping?.country = "PE"
        config.shipping?.postalCode = "15047"
        config.shipping?.documentType = "DNI"
        config.shipping?.document = "12345678"
        
        config.token = TokenPaymentIzipay()
        config.token?.cardToken = nil //requerido solo en action pay_token
        
        config.appearance = AppearencePaymentIzipay()
        config.appearance?.theme = "green"
        config.appearance?.logo = "https://logowik.com/content/uploads/images/shopping-cart5929.jpg" //es solo un ejemplo
        config.appearance?.formControls = AppearenceControlsPaymentIzipay()
        config.appearance?.formControls?.isAmountLabelVisible = true
        config.appearance?.formControls?.isLangControlVisible = true
        config.appearance?.language = "ESP"
        config.appearance?.visualSettings = AppearenceVisualSettingsPaymentIzipay() //inicializar el objeto antes de ponerle valores
        
        if self.swtModalidad.isOn {
            config.appearance?.visualSettings?.presentationMode = .embedded //Tomar en cuenta que la modalidad embebido requiere un mayor control de eventos y conocimiento de su app.
        } else {
            config.appearance?.visualSettings?.presentationMode = .fullscreen
        }
        
        config.appearance?.visualSettings?.showResultScreen = true
        
        
        /**
         * Integración con iOS - Paso 7
         * https://developers.izipay.pe/ios-core/integration-with-ios/#paso-7-integraci%C3%B3n-con-librer%C3%ADas-de-sensory-branding
         */
        //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
        
        config.urlIPN = "https://oalanya.com/izipay/ipn/" //enviar si se quiere notificaciones servidor a servidor
        
        return config
    }
    
    private func currentTimeMillis() -> Int64 {
        return Int64(Date().timeIntervalSince1970 * 1000 * 1000)
    }
    
    private func showSDKResponseOnScreen(_ paymentResult: PaymentResult) {
        /**
         * Integración con iOS - Paso 5
         * https://developers.izipay.pe/ios-core/integration-with-ios/#paso-5-agregar-los-m%C3%A9todos-del-delegate
         */
        print(paymentResult.code ?? "")
        print(paymentResult.message ?? "")
        print(paymentResult.description)
        self.txtvResult.text = paymentResult.description
        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
                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
                }
            } else {
                //La operacion no se completo o fue rechazada consultar/anular orden
            }
        } else {
            //Si no hay un codigo de error, consultar/anular orden
        }
    }
    
}

extension MainViewController : IzipayPaymentDelegate {
    
    /**
     * Integración con iOS - Paso 7
     * https://developers.izipay.pe/ios-core/integration-with-ios/#paso-7-integraci%C3%B3n-con-librer%C3%ADas-de-sensory-branding
     */
    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: .production, merchant: safeMerchant) { status in
                if status == .success {
                    self.sonicManager.play(with: mastercardview) { MCSonicStatus in
                        print(MCSonicStatus)
                    }
                }
            }
        }
    }
    
    func getPaymentResult(_ paymentResult: PaymentResult) {
        //Lectura de respuesta del SDK
        /**
         * Integración con iOS - Paso 5
         * https://developers.izipay.pe/ios-core/integration-with-ios/#paso-5-agregar-los-m%C3%A9todos-del-delegate
         * Actualizado al 27-08-2025
         */
        self.showSDKResponseOnScreen(paymentResult)
    }
    
    
    /**
     * Integración con iOS - Cybersource - Paso 4
     * https://developers.izipay.pe/ios-core/integration-with-cybersource/#paso-4
     */
    func executeProfiling(_ params: IzipayPayButtonSDK.ScoringParams) {
        //requerido para la deteccion de fraude de cybersource, solo si el comercio lo ha pedido, si no dejar en blanco este metodo
        let profilingConnections : RLTMXProfilingConnections  = RLTMXProfilingConnections.init()
        profilingConnections.connectionTimeout    = TimeInterval(params.timeout);
        profilingConnections.connectionRetryCount = Int32(params.intents);
        profile = RLTMXProfiling.sharedInstance()
        profile?.configure(configData:[
                            RLTMXOrgID              : params.userOrg ?? "",
                            RLTMXFingerprintServer  : params.defaultServer ?? "",
                            RLTMXProfileTimeout     : profilingConnections.connectionTimeout,
                            RLTMXProfilingConnectionsInstance: profilingConnections,
        ])
        self.doProfileRequest(forUser: params.userScoring ?? "", with: params.randomFp ?? "")
    }

    //requerido para la deteccion de fraude de cybersource, solo si el comercio lo ha pedido
    private func doProfileRequest(forUser userScoring : String, with id : String) {
        let customAttributes : [String : String] = [RLTMXSessionID: "\(userScoring)\(id)"]
        
        if let safeProfile = self.profile {
            let _: RLTMXProfileHandle =
            safeProfile.profileDevice(profileOptions:customAttributes,
                                      callbackBlock:{(result: [AnyHashable : Any]?) -> Void in
                let results:NSDictionary! = result! as NSDictionary
                let status:RLTMXStatusCode =
                RLTMXStatusCode(rawValue:(results.value(forKey: RLTMXProfileStatus) as!
                                          NSNumber).intValue)!
                _ = results.value(forKey: RLTMXSessionID) as! String
                if status == RLTMXStatusCode.ok {
                    // No errors, profiling succeeded!
                    // .RLTMXStatusCodeOk en lugar de .ok en versiones antiguas 
                }
            })
        }
    }

}

extension MainViewController : ForEmbedVCDelegate { //recibir la respuesta del sdk desde una pantalla(viewcontroller con containerView) que tiene embebido el SDK
    func passResponseToOrigin(_ paymentResult: PaymentResult) {
        self.showSDKResponseOnScreen(paymentResult)
    }
}
