/* Licensed Materials - Property of IBM
 * 5725-I43 (C) Copyright IBM Corp. 2018. All Rights Reserved.
 * US Government Users Restricted Rights - Use, duplication or
 * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
 */

/* author - Srihari Kulkarni | skulkarni@in.ibm.com | Slack - @Srihari */

import {
    Platform,
    NativeModules,
    NativeEventEmitter,
    DeviceEventEmitter
} from 'react-native';

var wlClient = NativeModules.RNWLClient;
const eventEmitter = new NativeEventEmitter(NativeModules.RNWLClient)

const emitterMap = new Map();

const _mandatoryParam = function(parameterName) { throw new Error('Error: Missing parameter ' + parameterName); };


/**
 *  This collection of topics lists the public methods of the IBM® MobileFirst® runtime client API 
 * for mobile apps, desktop, and web. WL.Client is a JavaScript client library that provides access to IBM MobileFirst capabilities. You can use WL.Client to perform the following types of functions:
 */
class WLClient {

    /** 
     * @ignore
     */
    constructor() {
        if (WLClient.instance) {
            return WLClient.instance;
        }
        WLClient.instance = this;

        /** THE FOLLOWING LINE OF CODE SHOULD NOT BE COMMENTED. IT IS ONLY COMMENTED OUT FOR DOC GENERATION */
        if (Platform.OS === 'ios') {
            eventEmitter.addListener('mobileFirstExceptionEvent', function(e: Event) {
                console.error("Exception occurred ");
                console.error("Message : " + e.message);
                console.error("Cause : " + e.cause);
            });
        } else {
            DeviceEventEmitter.addListener('mobileFirstExceptionEvent', function(e: Event) {
                console.error("Exception occurred ");
                console.error("Message : " + e.message);
                console.error("Cause : " + e.cause);
            });
        }
        return WLClient.instance;
    }

    /**
     * Adds a HTTP header to all requests made by the MobileFirst SDK. 
     * Use the WLClient.removeGlobalHeader API to stop adding the header to further requests 
     * @param {string} name - Name of the HTTP header 
     * @param {string} value  - The value of the HTTP header
     */
    addGlobalHeader(name = _mandatoryParam('name'), value = _mandatoryParam('value')) {
        wlClient.addGlobalHeader(name, value);
    }

    /**
     * Send an answer back to the security check that triggered this challenge. 
     * The answer should be in a JSON format.
     * @param {string} securityCheckName - The security check name that represents the challenge. Used to identify which security check requires authentication.
     * @param {object} answer - The challenge answer to be returned to the server. For example, this could be credentials collected from the user. 
     */
    submitChallengeAnswer(securityCheckName = _mandatoryParam('securityCheckName'), answer = _mandatoryParam('answer')) {
        wlClient.submitChallengeAnswer(securityCheckName, answer);
    }

    /**
     * Gets the display name of the device. 
     * The display name is retrieved from the MobileFirst Server registration data. 
     * You can see the device display name in the Devices section of the MobileFirst Console.
     * 
     * @return {Promise<string>} The display name of the device. For example, "Sam's iPhone"
     */
    async getDeviceDisplayName() {
        var deviceName = await wlClient.getDeviceDisplayName();
        return deviceName;
    }

    /**
     * Sets the friendly name of the device.
     * You can see the device display name in the Devices section of the MobileFirst console.
     * @param {string} deviceDisplayName - The friendly name to be set for the device.
     */
    async setDeviceDisplayName(deviceDisplayName = _mandatoryParam('deviceDisplayName')) {
        var response = await wlClient.setDeviceDisplayName(deviceDisplayName);
        return response;
    }

    /**
     * Returns the current MobileFirst Platform server URL. 
     * You can define the server URL in the mfpclient.properties (Android) / mfpclient.plist (iOS) or by calling the WLClient.setServerUrl API
     * @return {Promise<string>} The URL of the current MobileFirst Platform server. 
     */
    async getServerUrl() {
        var serverUrl = await wlClient.getServerUrl();
        return serverUrl;
    }

    /**
     * 
     * @param {string} serverUrl - The URL of the MobileFirst Platform server to point to. 
     * @example 
     * var newserverurl = 'https://mobilefoundation-newserver.mybluemix.net:443/mfp' ;
     * WLClient.setServerUrl(newserverurl);
     */
    setServerUrl(serverUrl = _mandatoryParam('serverUrl')) {
        wlClient.setServerUrl(serverUrl);
    }

    /**
     * The number of seconds between which a heartbeat request is sent to the MobileFirst server to keep the connection alive. 
     * The default interval is 7 minutes or 420 seconds. Heartbeats are sent only when the app is in the foreground.
     * @param {number} heartbeatIntervalInSeconds - Heartbeat interval value in seconds
     */
    setHeartbeatInterval(heartbeatIntervalInSeconds = _mandatoryParam('heartbeatIntervalInSeconds')) {
        wlClient.setHeartbeatInterval(heartbeatIntervalInSeconds);
    }

    /**
     * Pins the host X509 certificate public key to the client application. 
     * Secured calls to the pinned remote host will be checked for a public key match. 
     * Secured calls to other hosts containing other certificates will be rejected. 
     * Some mobile operating systems might cache the certificate validation check results. 
     * Your app must call the certificate pinning method before making a secured request. 
     * Calling this method a second time overrides any previous pinning operation.
     * The certificates must be in DER format. When multiple certificates are pinned, a secured call is checked for a match with any one of the certificates. 
     * @param {string[]} certificateFileNames - The list of paths to the certificate files. On Android this will be under the assets folder. 
     */
    pinTrustedCertificatesPublicKey(certificateFileNames = _mandatoryParam('certificateFileNames')) {
        wlClient.pinTrustedCertificatesPublicKey(certificateFileNames);
    }

    /**
     * Register a challenge handler to handle act upon challenges provided for a given security check.
     * @param {ChallengeHandler} challengeHandlerClass - The challenge handler object implementing the methods of a SecurityCheck Challenge handler
     * @param {string} securityCheckName - The name of the security check for which this challenge handler must respond.
     * @example
     * class UserLoginCH { 
     * 
     *    constructor() {} 
     *    
     *    handleChallenge(params){
     *      // Gather credentials from the user
     *      WLClient.submitChallengeAnswer (securityCheck, credentials); 
     *    }
     * 
     *    handleSuccess(){
     *      // Handle success. Perhaps show a success message or do nothing. 
     *    }
     * 
     *    handleFailure(){
     *       // Handle failure. Perhaps, show a failure message or ask for credentials again.
     *    }
     * }
     * 
     * var userLoginCH = new UserLoginCH(); 
     * WLClient.registerChallengeHandler(userLoginCH ,"UserLogin") ; 
     *
     */
    registerChallengeHandler(challengeHandlerClass = _mandatoryParam('challengeHandlerClass'),
        securityCheckName = _mandatoryParam('securityCheckName')) {
        wlClient.registerChallengeHandler(securityCheckName);

        var emitter;
        if (Platform.OS === 'ios') {
            emitter = eventEmitter;
        } else {
            emitter = DeviceEventEmitter;
        }

        if (emitterMap.has(securityCheckName)) {
            var subscriptions = emitterMap.get(securityCheckName);
            subscriptions.forEach(subscription => {
                subscription.remove()
            });
        }

        /** THE FOLLOWING LINE OF CODE SHOULD NOT BE COMMENTED. IT IS ONLY COMMENTED OUT FOR DOC GENERATION */
        
        var subscriptions = [];
        subscriptions.push(emitter.addListener('handleChallengeEvent' + securityCheckName, function(e: Event) {
            challengeHandlerClass.handleChallenge(e);
        }));
        
        subscriptions.push(emitter.addListener('challengeSuccessEvent' + securityCheckName, function(e: Event) {
            challengeHandlerClass.handleSuccess(e);
        }));
        
        subscriptions.push(emitter.addListener('challengeFailureEvent' + securityCheckName, function(e: Event) {
            challengeHandlerClass.handleFailure(e);
        }));
        
        emitterMap.set(securityCheckName, subscriptions);
    }
}

export default WLClient