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


import SmartechBaseReactNative from './specs/NativeSmartechBaseReactNative';


const SmartechEventEmitter = Platform.select({
  ios: new NativeEventEmitter(SmartechBaseReactNative),
  android: DeviceEventEmitter
});



function defaultCallback(method: string, err: any, res: any) {
  if (err) {
    console.log('Smartech ' + method + ' default callback error', err);
  }
  else {
    console.log('Smartech ' + method + ' default callback result', res);
  }
}

// Used to handle callback
function callWithCallback(this: any, method: string, args: any[] | null, callback: ((err: any, res: any) => void) | null) {
  if (typeof callback === 'undefined' || callback == null || typeof callback !== 'function') {
    callback = (err, res) => {
      defaultCallback(method, err, res);
    };
  }
  if (args == null) {
    args = [];
  }
  args.push(callback);
  (SmartechBaseReactNative as any)[method].apply(this, args);
}

// Store event subscriptions for cleanup
const eventMap: { [key: string]: any } = {};

var SmartechBaseReact = {

  // All the constants declared in the Smartech React Bridge.
  SmartechDeeplink: SmartechBaseReactNative.getConstants().SmartechDeeplink,
  SmartechWidgetDataReceived: SmartechBaseReactNative.getConstants().SmartechWidgetDataReceived,

  // This method is used to register listener.
  addListener: function (eventName: string, handler: (data: any) => void) {
    if (SmartechEventEmitter) {
      const subscription = SmartechEventEmitter.addListener(eventName, handler);
      if (eventName == 'SmartechDeeplink') {
        SmartechBaseReactNative.setDeeplinkInit();
      }
      // Store in eventMap for backward compatibility
      eventMap[eventName] = subscription;
      // Return subscription so user can remove it manually
      return subscription;
    }
    return undefined;
  },

  // This method is used to unregister registered listener.
  removeListener: function (eventName: string) {
    if (eventMap[eventName]) {
      eventMap[eventName].remove();
      delete eventMap[eventName];
    }
  },

  /**
   * This method is used to track app update event.
   * This method should be called by the developer to track the app updates event to Smartech.
   */
  trackAppInstall: function () {
    SmartechBaseReactNative.trackAppInstall();
  },

  /**
   * This method is used to track app update event.
   * This method should be called by the developer to track the app updates event to Smartech.
   */
  trackAppUpdate: function () {
    SmartechBaseReactNative.trackAppUpdate();
  },

  /**
   * This method is used to track app install or update event by Smartech SDK itself.
   * This method should be called by the developer to track the app install or update event by Smartech SDK itself.
   * If you are calling this method then you should not call trackAppInstall or trackAppUpdate method.
   */
  trackAppInstallUpdateBySmartech: function () {
    SmartechBaseReactNative.trackAppInstallUpdateBySmartech();
  },

  /**
   * This method is used to track custom event done by the user.
   * This method should be called by the developer to track any custom activites
   * that is performed by the user in the app to Smartech backend.
   */
  trackEvent: function (eventName: string, payload: any) {
    SmartechBaseReactNative.trackEvent(eventName, payload);
  },

  /**
   * This method is used to send login event to Smartech backend.
   * This method should be called only when the app gets the user's identity
   * or when the user does a login activity in the application.
   */
  login: function (identity: string) {
    SmartechBaseReactNative.login(identity);
  },

  /**
   * This method would logout the user and clear identity on Smartech backend.
   * This method should be called only when the user log out of the application.
   */
  logoutAndClearUserIdentity: function (isLougoutClearIdentity: boolean) {
    SmartechBaseReactNative.logoutAndClearUserIdentity(isLougoutClearIdentity)
  },

  /**
   * This method would set the user identity locally and with all subsequent events this identity will be send.
   * This method should be called only when the user gets the identity.
   */
  setUserIdentity: function (identity: string, callback: ((err: any, res: any) => void) | null) {
    callWithCallback('setUserIdentity', [identity], callback);
  },

  /**
    * This method would get the user identity that is stored in the SDK.
    * This method should be called to get the user's identity.
    */
  getUserIdentity: function (callback: ((err: any, res: any) => void) | null) {
    callWithCallback('getUserIdentity', null, callback);
  },

  /**
   * This method would clear the identity that is stored in the SDK.
   * This method will clear the user's identity by removing it from.
   */
  clearUserIdentity: function () {
    SmartechBaseReactNative.clearUserIdentity();
  },

  /**
   * This method is used to update the user profile.
   * This method should be called by the developer to update all the user related attributes to Smartech.
   */
  updateUserProfile: function (profilePayload: any) {
    SmartechBaseReactNative.updateUserProfile(profilePayload);
  },

  // ----- GDPR Methods -----

  /**
   * This method is used to opt tracking.
   * If you call this method then we will opt in or opt out the user of tracking.
   */
  optTracking: function (isTrackingOpted: boolean) {
    SmartechBaseReactNative.optTracking(isTrackingOpted);
  },

  /**
   * This method is used to get the current status of opt tracking.
   * If you call this method you will get the current status of the tracking which can be used to render the UI at app level.
   */
  hasOptedTracking: function (callback: ((err: any, res: any) => void) | null) {
    callWithCallback('hasOptedTracking', null, callback);
  },

  /**
   * This method is used to opt in-app messages.
   * If you call this method then we will opt in or opt out the user of in-app messages.
   */
  optInAppMessage: function (isInappOpted: boolean) {
    SmartechBaseReactNative.optInAppMessage(isInappOpted);
  },

  /**
   * This method is used to get the current status of opt in-app messages.
   * If you call this method you will get the current status of the opt in-app messages which can be used to render the UI at app level.
   */
  hasOptedInAppMessage: function (callback: ((err: any, res: any) => void) | null) {
    callWithCallback('hasOptedInAppMessage', null, callback);
  },

  // ----- Location Methods -----

  /**
   * This method is used to set the user's location to the SDK.
   * You need to call this method to set location which will be passed on the Smartech SDK.
   */
  setUserLocation: function (latitude: number, longitude: number) {
    SmartechBaseReactNative.setUserLocation(latitude, longitude);
  },

  // ----- Helper Methods -----

  /**
   * This method is used to get the app id used by the Smartech SDK.
   * If you call this method you will get the app id used by the Smartech SDK.
   */

  getAppId: function (callback: ((err: any, res: any) => void) | null) {
    callWithCallback('getAppId', null, callback);
  },

  /**
  * Retrieves the Unbxd identity by the Smartech SDK..
  */

  getNetcoreUnbxdIdentity: function (callback: ((err: any, res: any) => void) | null) {
    callWithCallback('getNetcoreUnbxdIdentity', null, callback);
  },

  /**
  * Retrieves the Partner parameters by the Smartech SDK..
  */

  getPartnerParametersString: function (callback: ((err: any, res: any) => void) | null) {
    callWithCallback('getPartnerParametersString', null, callback);
  },

  /**
   * This method is used to get the device unique id used by Smartech SDK.
   * If you call this method you will get the device unique id which is used to identify a device on Smartech.
   */

  getDeviceGuid: function (callback: ((err: any, res: any) => void) | null) {
    callWithCallback('getDeviceGuid', null, callback);
  },

  /**
   * This method is used to get the current Smartech SDK version.
   * If you call this method you will get the current Smartech SDK version used inside the app.
   */
  getSDKVersion: function (callback: ((err: any, res: any) => void) | null) {
    callWithCallback('getSDKVersion', null, callback);
  },

  /**
     * This method is used to get all widget names.
     * If you call this method you will get an array of all widget names.
     */
  getAllWidgetNames: function (callback: ((err: any, res: any) => void) | null) {
    callWithCallback('getAllWidgetNames', null, callback);
  },

  /**
   * This method is used to get widget by name.
   * This method should be called with a specific widget name.
   */
  getWidgetByName: function (widgetName: string) {
    SmartechBaseReactNative.getWidgetByName(widgetName);
  },

  /**
   * This method is used to get widgets by names.
   * This method should be called with an array of widget names.
   */
  getWidgetByNames: function (widgetNames: string[]) {
    SmartechBaseReactNative.getWidgetByNames(widgetNames);
  },

  /**
   * This method is used to get all widgets.
   * This method will fetch all available widgets.
   */
  getAllWidgets: function () {
    SmartechBaseReactNative.getAllWidgets();
  },

  trackWidgetAsViewed: function (widget: object) {
    SmartechBaseReactNative.trackWidgetAsViewed(widget)
  },

  trackWidgetAsClicked: function (widget: object) {
    SmartechBaseReactNative.trackWidgetAsClicked(widget)
  }

};

export default SmartechBaseReact;

//module.exports = SmartechBaseReact;
