/*
 * Copyright (c) 2016-present Invertase Limited & Contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this library except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

import {
  isAndroid,
  isBoolean,
  isFunction,
  isIOS,
  isString,
  isUndefined,
} from '@react-native-firebase/app/lib/common';
import {
  createModuleNamespace,
  FirebaseModule,
  getFirebaseRoot,
} from '@react-native-firebase/app/lib/internal';
import { AppRegistry } from 'react-native';
import remoteMessageOptions from './remoteMessageOptions';
import version from './version';

const statics = {};

const namespace = 'messaging';

const nativeModuleName = 'RNFBMessagingModule';

class FirebaseMessagingModule extends FirebaseModule {
  constructor(...args) {
    super(...args);
    this._isAutoInitEnabled = this.native.isAutoInitEnabled || true;
    this._isRegisteredForRemoteNotifcations = this.native.isRegisteredForRemoteNotifcations || true;
  }

  get isAutoInitEnabled() {
    return this._isAutoInitEnabled;
  }

  /**
   * @platform ios
   */
  get isRegisteredForRemoteNotifications() {
    if (isAndroid) {
      return true;
    }
    return this._isRegisteredForRemoteNotifcations;
  }

  setAutoInitEnabled(enabled) {
    if (!isBoolean(enabled)) {
      throw new Error(
        "firebase.messaging().setAutoInitEnabled(*) 'enabled' expected a boolean value.",
      );
    }

    this._isAutoInitEnabled = enabled;
    return this.native.setAutoInitEnabled(enabled);
  }

  getToken(authorizedEntity, scope) {
    if (!isUndefined(authorizedEntity) && !isString(authorizedEntity)) {
      throw new Error(
        "firebase.messaging().getToken(*) 'authorizedEntity' expected a string value.",
      );
    }

    if (!isUndefined(scope) && !isString(scope)) {
      throw new Error("firebase.messaging().getToken(_, *) 'scope' expected a string value.");
    }

    return this.native.getToken(
      authorizedEntity || this.app.options.messagingSenderId,
      scope || 'FCM',
    );
  }

  deleteToken(authorizedEntity, scope) {
    if (!isUndefined(authorizedEntity) && !isString(authorizedEntity)) {
      throw new Error(
        "firebase.messaging().deleteToken(*) 'authorizedEntity' expected a string value.",
      );
    }

    if (!isUndefined(scope) && !isString(scope)) {
      throw new Error("firebase.messaging().deleteToken(_, *) 'scope' expected a string value.");
    }

    return this.native.deleteToken(
      authorizedEntity || this.app.options.messagingSenderId,
      scope || 'FCM',
    );
  }

  onMessage(listener) {
    if (!isFunction(listener)) {
      throw new Error("firebase.messaging().onMessage(*) 'listener' expected a function.");
    }

    // TODO(salakar) rework internals as without this native module will never be ready (therefore never subscribes)
    this.native;

    const subscription = this.emitter.addListener('messaging_message_received', listener);
    return () => subscription.remove();
  }

  onTokenRefresh(listener) {
    if (!isFunction(listener)) {
      throw new Error("firebase.messaging().onTokenRefresh(*) 'listener' expected a function.");
    }

    // TODO(salakar) rework internals as without this native module will never be ready (therefore never subscribes)
    this.native;

    const subscription = this.emitter.addListener('messaging_token_refresh', listener);
    return () => subscription.remove();
  }

  /**
   * @platform ios
   */
  requestPermission() {
    if (isAndroid) {
      return Promise.resolve(true);
    }
    return this.native.requestPermission();
  }

  /**
   * @platform ios
   */
  registerForRemoteNotifications() {
    if (isAndroid) {
      return Promise.resolve();
    }
    this._isRegisteredForRemoteNotifcations = true;
    return this.native.registerForRemoteNotifications();
  }

  /**
   * @platform ios
   */
  unregisterForRemoteNotifications() {
    if (isAndroid) {
      return Promise.resolve();
    }
    this._isRegisteredForRemoteNotifcations = false;
    return this.native.unregisterForRemoteNotifications();
  }

  /**
   * @platform ios
   */
  getAPNSToken() {
    if (isAndroid) {
      return Promise.resolve(null);
    }
    return this.native.getAPNSToken();
  }

  hasPermission() {
    return this.native.hasPermission();
  }

  // https://firebase.google.com/docs/reference/android/com/google/firebase/messaging/FirebaseMessagingService.html#public-void-ondeletedmessages-
  onDeletedMessages(listener) {
    if (!isFunction(listener)) {
      throw new Error("firebase.messaging().onDeletedMessages(*) 'listener' expected a function.");
    }

    // TODO(salakar) rework internals as without this native module will never be ready (therefore never subscribes)
    this.native;

    const subscription = this.emitter.addListener('messaging_message_deleted', listener);
    return () => subscription.remove();
  }

  // https://firebase.google.com/docs/reference/android/com/google/firebase/messaging/FirebaseMessagingService.html#onMessageSent(java.lang.String)
  onMessageSent(listener) {
    if (!isFunction(listener)) {
      throw new Error("firebase.messaging().onMessageSent(*) 'listener' expected a function.");
    }

    // TODO(salakar) rework internals as without this native module will never be ready (therefore never subscribes)
    this.native;

    const subscription = this.emitter.addListener('messaging_message_sent', listener);
    return () => {
      subscription.remove();
    };
  }

  // https://firebase.google.com/docs/reference/android/com/google/firebase/messaging/FirebaseMessagingService.html#onSendError(java.lang.String,%20java.lang.Exception)
  onSendError(listener) {
    if (!isFunction(listener)) {
      throw new Error("firebase.messaging().onSendError(*) 'listener' expected a function.");
    }

    // TODO(salakar) rework internals as without this native module will never be ready (therefore never subscribes)
    this.native;

    const subscription = this.emitter.addListener('messaging_message_send_error', listener);
    return () => subscription.remove();
  }

  /**
   * @platform android
   */
  setBackgroundMessageHandler(handler) {
    if (!isFunction(handler)) {
      throw new Error(
        "firebase.messaging().setBackgroundMessageHandler(*) 'handler' expected a function.",
      );
    }

    if (isIOS) {
      return;
    }

    AppRegistry.registerHeadlessTask('ReactNativeFirebaseMessagingHeadlessTask', () => handler);
  }

  sendMessage(remoteMessage) {
    let options;
    try {
      options = remoteMessageOptions(this.app.options.messagingSenderId, remoteMessage);
    } catch (e) {
      throw new Error(`firebase.messaging().sendMessage(*) ${e.message}.`);
    }

    return this.native.sendMessage(options);
  }

  subscribeToTopic(topic) {
    if (!isString(topic)) {
      throw new Error("firebase.messaging().subscribeToTopic(*) 'topic' expected a string value.");
    }

    if (topic.indexOf('/') > -1) {
      throw new Error('firebase.messaging().subscribeToTopic(*) \'topic\' must not include "/".');
    }

    return this.native.subscribeToTopic(topic);
  }

  unsubscribeFromTopic(topic) {
    if (!isString(topic)) {
      throw new Error(
        "firebase.messaging().unsubscribeFromTopic(*) 'topic' expected a string value.",
      );
    }

    if (topic.indexOf('/') > -1) {
      throw new Error(
        'firebase.messaging().unsubscribeFromTopic(*) \'topic\' must not include "/".',
      );
    }

    return this.native.unsubscribeFromTopic(topic);
  }

  /**
   * unsupported
   */

  useServiceWorker() {
    // eslint-disable-next-line no-console
    console.warn(
      'firebase.messaging().useServiceWorker() is not supported on react-native-firebase.',
    );
  }

  usePublicVapidKey() {
    // eslint-disable-next-line no-console
    console.warn(
      'firebase.messaging().usePublicVapidKey() is not supported on react-native-firebase.',
    );
  }
}

// import { SDK_VERSION } from '@react-native-firebase/messaging';
export const SDK_VERSION = version;

// import messaging from '@react-native-firebase/messaging';
// messaging().X(...);
export default createModuleNamespace({
  statics,
  version,
  namespace,
  nativeModuleName,
  nativeEvents: [
    'messaging_token_refresh',
    'messaging_message_sent',
    'messaging_message_deleted',
    'messaging_message_received',
    'messaging_message_send_error',
  ],
  hasMultiAppSupport: false,
  hasCustomUrlOrRegionSupport: false,
  ModuleClass: FirebaseMessagingModule,
});

// import messaging, { firebase } from '@react-native-firebase/messaging';
// messaging().X(...);
// firebase.messaging().X(...);
export const firebase = getFirebaseRoot();
