package com.tencent.qcloud.rntimpush;

import android.content.Context;
import android.util.Log;

import com.google.gson.Gson;

import androidx.annotation.NonNull;
import javax.annotation.Nullable;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.modules.core.DeviceEventManagerModule;

import com.tencent.qcloud.tim.push.TIMPushManager;
import com.tencent.qcloud.tim.push.TIMPushCallback;
import com.tencent.qcloud.tim.push.TIMPushListener;
import com.tencent.qcloud.tim.push.TIMPushMessage;
import com.tencent.qcloud.tim.push.config.TIMPushConfig;

import com.facebook.react.bridge.Callback;

@ReactModule(name = TencentCloudPushModule.NAME)
public class TencentCloudPushModule extends ReactContextBaseJavaModule {
  private Context mContext;
  private String mExtInfo = "";
  private String LOG_PREFIX = "Push java |";
  public static final String NAME = "TencentCloudPush";

  public static TencentCloudPushModule instance;
  public static ReactApplicationContext rContext;

  private int listenerCount = 0;
  private Gson gson = new Gson();

  private TIMPushListener pushListener = null;

  public TencentCloudPushModule(ReactApplicationContext reactContext) {
    super(reactContext);
    rContext = reactContext;
    mContext = reactContext.getApplicationContext();
    instance = this;
    pushListener = null;
  }

  @Override
  @NonNull
  public String getName() {
    return NAME;
  }

  @ReactMethod
  public void registerPush(int SDKAppID, String appKey, Callback onSucc) {
    Log.i(NAME, LOG_PREFIX + " registerPush | " + SDKAppID + " " + appKey);
    setRunningPlatform();
    TIMPushManager.getInstance().registerPush(mContext, SDKAppID, appKey, new TIMPushCallback() {
        @Override
        public void onSuccess(Object data) {
          onSucc.invoke(data);
          if (data != null) {
            String token = (String)data;
            Log.i(NAME, LOG_PREFIX + " registerPush ok | " + token);
          }
        }
        
        @Override    
        public void onError(int errCode, String errMsg, Object data) { 
          Log.i(NAME, LOG_PREFIX + " registerPush failed | " + errCode + " " + errMsg);
        }
    });
  }

  @ReactMethod
  public void registerPushWithOnError(int SDKAppID, String appKey, Callback onSucc, Callback onErr) {
    Log.i(NAME, LOG_PREFIX + " registerPushWithOnError " + SDKAppID + " " + appKey);
    setRunningPlatform();
    TIMPushManager.getInstance().registerPush(mContext, SDKAppID, appKey, new TIMPushCallback() {
        @Override
        public void onSuccess(Object data) {
          onSucc.invoke(data);
          if (data != null) {
            String token = (String)data;
            Log.i(NAME, LOG_PREFIX + " registerPush ok | " + token);
          }
        }
        
        @Override    
        public void onError(int errCode, String errMsg, Object data) { 
          Log.i(NAME, LOG_PREFIX + " registerPush failed | " + errCode + " " + errMsg);
          onErr.invoke(errCode, errMsg);
        }
    });
  }


  @ReactMethod
  public void unRegisterPush(Callback onSucc) {
    Log.i(NAME, LOG_PREFIX + " unRegisterPush");
    TIMPushManager.getInstance().unRegisterPush(new TIMPushCallback() {
      @Override
        public void onSuccess(Object data) {
          Log.i(NAME, LOG_PREFIX + " unRegisterPush ok - ");
          onSucc.invoke();
        }
    });
  }

  @ReactMethod
  public void unRegisterPushWithOnError(Callback onSucc) {
    Log.i(NAME, LOG_PREFIX + " unRegisterPushWithOnError");
    TIMPushManager.getInstance().unRegisterPush(new TIMPushCallback() {
      @Override
      public void onSuccess(Object data) {
        Log.i(NAME, LOG_PREFIX + " unRegisterPushWithOnError ok - ");
        onSucc.invoke();
      }
    });
  }

  @ReactMethod
  public void getRegistrationID(Callback onSucc) {
    TIMPushManager.getInstance().getRegistrationID(new TIMPushCallback() {
      @Override
      public void onSuccess(Object data) {
        if (data != null) {
          String ret = (String)data;
          Log.i(NAME, LOG_PREFIX + " getRegistrationID ok | " + ret);
          onSucc.invoke(ret);
        }
      }
    });
  }

  @ReactMethod
  public void setRegistrationID(String registrationID, Callback onSucc) {
    TIMPushManager.getInstance().setRegistrationID(registrationID, new TIMPushCallback() {
      @Override
      public void onSuccess(Object data) {
        Log.i(NAME, LOG_PREFIX + " setRegistrationID ok");
        onSucc.invoke();
      }
    });
  }

  @ReactMethod
  public void getNotificationExtInfo(Callback onSucc) {
    onSucc.invoke(mExtInfo);
  }

  public void storeExtInfo(String extInfo) {
    Log.i(NAME, LOG_PREFIX = " storeExtInfo | " + extInfo);
    mExtInfo = extInfo;
  }

  private void setRunningPlatform() {
    TIMPushConfig.getInstance().setRunningPlatform(5);
  }

  private void sendEvent(String eventName, @Nullable WritableMap params) {
    rContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, params);
  }

  // Will be called when this module's first listener is add.
  @ReactMethod
  public void addListener(String eventName) {
    if (listenerCount == 0) {
      addPushListener();
    }
    listenerCount += 1;
  }

  // Will be called when this module's last listener is removed.
  @ReactMethod
  public void removeListeners(Integer count) {
    listenerCount -= count;
    if (listenerCount == 0) {
      removePushListener();
    }
  }

  @ReactMethod
  public void addPushListener() {
    Log.i(NAME, LOG_PREFIX + " addPushListener ");
    pushListener = new TIMPushListener() {
      @Override
      public void onRecvPushMessage(TIMPushMessage message) {
        WritableMap params = Arguments.createMap();
        params.putString("data", gson.toJson(message));
        sendEvent("message_received", params);
      }

      @Override
      public void onRevokePushMessage(String messageID) {
        WritableMap params = Arguments.createMap();
        params.putString("data", messageID);
        sendEvent("message_revoked", params);
      }

      @Override
      public void onNotificationClicked(String ext) {
        WritableMap params = Arguments.createMap();
        params.putString("data", ext);
        sendEvent("notification_clicked", params);
      }
    };
    TIMPushManager.getInstance().addPushListener(pushListener);
  }

  @ReactMethod
  public void removePushListener() {
    Log.i(NAME, LOG_PREFIX + " removePushListener");
    if(pushListener == null) {
      return;
    }
    TIMPushManager.getInstance().removePushListener(pushListener);
    pushListener = null;
  }

  @ReactMethod
  public void disablePostNotificationInForeground(Boolean disable) {
    Log.i(NAME, LOG_PREFIX + " disablePostNotificationInForeground");
    TIMPushManager.getInstance().disablePostNotificationInForeground(disable);
  }

  @ReactMethod
  public void createNotificationChannel(String options, Callback onSucc) {
    Log.i(NAME, LOG_PREFIX + " createNotificationChannel");
    TIMPushManager.getInstance().callExperimentalAPI("createNotificationChannel", options, new TIMPushCallback() {
        @Override
        public void onSuccess(Object data) {
          onSucc.invoke(data);
        }
    });
  }
}
