import NativeRNFusedLocation from './specs/v1/NativeRNFusedLocation';
import { NativeEventEmitter, Platform } from 'react-native';

const LocationEventEmitter = new NativeEventEmitter(NativeRNFusedLocation);

const noop = () => {};
let subscriptions = [];
let updatesEnabled = false;

const Geolocation = {
  setRNConfiguration: (config) => {}, // eslint-disable-line no-unused-vars

  requestAuthorization: async (authorizationLevel) => {
    if (Platform.OS !== 'ios' && Platform.OS !== 'harmony') {
      return Promise.reject('requestAuthorization is only for iOS');
    }

    if (!authorizationLevel) {
      // eslint-disable-next-line no-console
      console.error('authorizationLevel must be provided');
    }

    return NativeRNFusedLocation.requestAuthorization(authorizationLevel);
  },

  getCurrentPosition: (success, error = noop, options = {}) => {
    if (!success) {
      // eslint-disable-next-line no-console
      console.error('Must provide a success callback');
    }

    // Right now, we're assuming user already granted location permission.
    NativeRNFusedLocation.getCurrentPosition(options, success, error);
  },

  watchPosition: (success, error = null, options = {}) => {
    if (!success) {
      // eslint-disable-next-line no-console
      console.error('Must provide a success callback');
    }

    if (!updatesEnabled) {
      NativeRNFusedLocation.startObserving(options);
      updatesEnabled = true;
    } else if (Platform.OS === 'harmony') {
      // Harmony keeps a single native locationChange request. If JS state is stale
      // after all watchers were cleared without stopObserving, restart observing.
      const hasActiveWatcher = subscriptions.some(sub => sub !== undefined);
      if (!hasActiveWatcher) {
        NativeRNFusedLocation.stopObserving();
        NativeRNFusedLocation.startObserving(options);
        updatesEnabled = true;
      }
    }

    const watchID = subscriptions.length;

    subscriptions.push([
      LocationEventEmitter.addListener('geolocationDidChange', success),
      error ? LocationEventEmitter.addListener('geolocationError', error) : null
    ]);

    return watchID;
  },

  clearWatch: (watchID) => {
    const sub = subscriptions[watchID];

    if (!sub) {
      // Silently exit when the watchID is invalid or already cleared
      // This is consistent with timers
      return;
    }

    sub[0].remove();

    const sub1 = sub[1];

    if (sub1) {
      sub1.remove();
    }

    subscriptions[watchID] = undefined;

    let noWatchers = true;

    for (let ii = 0; ii < subscriptions.length; ii += 1) {
      if (subscriptions[ii]) {
        noWatchers = false; // still valid subscriptions
      }
    }

    if (noWatchers) {
      Geolocation.stopObserving();
    }
  },

  stopObserving: () => {
    if (updatesEnabled) {
      NativeRNFusedLocation.stopObserving();
      updatesEnabled = false;

      for (let ii = 0; ii < subscriptions.length; ii += 1) {
        const sub = subscriptions[ii];
        if (sub) {
          // eslint-disable-next-line no-console
          console.warn('Called stopObserving with existing subscriptions.');
          sub[0].remove();

          const sub1 = sub[1];

          if (sub1) {
            sub1.remove();
          }
        }
      }

      subscriptions = [];
    }
  }
};

export default Geolocation;