package com.onmeetingsdk;


import androidx.annotation.NonNull;

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

import com.onmeeting.videomeeting.AppSettings;
import com.onmeeting.videomeeting.IMeetingListener;
import com.onmeeting.videomeeting.OnMeetingSdk;
import com.onmeeting.videomeeting.http.connector.MeetingConnector;
import com.onmeeting.videomeeting.http.request.OpenRoomRequest;
import com.onmeeting.videomeeting.http.response.OpenRoomResponse;

import java.util.HashMap;

@ReactModule(name = OnmeetingSdkModule.NAME)
public class OnmeetingSdkModule extends ReactContextBaseJavaModule implements IMeetingListener {
    public static final String NAME = "OnmeetingSdk";
    private final ReactApplicationContext reactContext;
    OnMeetingSdk sdk;

    private IRNOnMeetingMeetViewReference mOnMeetingMeetViewReference;
    public OnmeetingSdkModule(ReactApplicationContext reactContext, IRNOnMeetingMeetViewReference onMeetingMeetViewReference) {
        super(reactContext);
        this.reactContext = reactContext;
        mOnMeetingMeetViewReference = onMeetingMeetViewReference;
    }

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


    @ReactMethod
    public void multiply(double a, double b, Promise promise) {
        promise.resolve(a - b);
    }

    @ReactMethod
    public void initSdk(Promise promise) {
        try {
            if (sdk != null) {
                promise.reject("SDK_INITIALIZED");
                return;
            }

            sdk = new OnMeetingSdk(reactContext);
            sdk.setListener(this);
            promise.resolve("OK");
        } catch (Exception e) {
            e.printStackTrace();
            promise.reject("EXCEPTION", e);
        }
    }

    @ReactMethod
    public void openMeeting(String publicKey, String accessToken, Promise promise) {
        if (publicKey == null || publicKey.isEmpty()) {
            promise.reject("OPEN_MEETING_ERROR", "'publicKey' is required");
            return;
        }


        if (accessToken == null || accessToken.isEmpty()) {
            promise.reject("OPEN_MEETING_ERROR", "'accessToken' is required");
            return;
        }

        try {
            OpenRoomResponse res = MeetingConnector.OpenRoom(new OpenRoomRequest(publicKey, accessToken));
            if (res == null) {
                promise.reject("OPEN_MEETING_ERROR", "Connect to API server failed");
                return;
            }

            if (res.isError()){
                promise.reject("OPEN_MEETING_ERROR", res.getMessage());
                return;
            }

            String meetingUrl = AppSettings.MeetingServiceUrl + "/" + res.getData().getMeetingId() + "?jwt=" + res.getData().getAccessToken();
            RNOnMeetingMeetConferenceOptions options = new RNOnMeetingMeetConferenceOptions.Builder()
                    .setRoom(meetingUrl)
                    .build();

            UiThreadUtil.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mOnMeetingMeetViewReference.getOnMeetingMeetView().join(options);
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
            promise.reject("EXCEPTION", e);
        }

//    if (sdk == null) {
//      initSdk(promise);
//    }

//    try {
//      OpenMeetingResult result = sdk.openMeeting(publicKey, accessToken);
//      if (result.isError()) {
//        promise.reject("OPEN_MEETING_ERROR", result.getMessage());
//        return;
//      }
//
//      promise.resolve("OK");
//    } catch (Exception e) {
//      e.printStackTrace();
//      promise.reject("EXCEPTION", e);
//    }
    }

    @ReactMethod
    public void destroy(Promise promise) {
        if (sdk != null) {
            try {
                sdk.destroy();
                sdk = null;
                promise.resolve("OK");
            } catch (Exception e) {
                e.printStackTrace();
                promise.reject("EXCEPTION", e);
            }
        }
    }

    @Override
    public void onConferenceJoined(HashMap<String, Object> hashMap) {
        WritableMap map = Arguments.createMap();
        try {
            map.putString("url", hashMap.get("url").toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("onConferenceJoined", map);
    }

    @Override
    public void onConferenceTerminated(HashMap<String, Object> hashMap) {
        WritableMap map = Arguments.createMap();
        try {
            map.putString("url", hashMap.get("url").toString());
            map.putString("error", hashMap.get("error").toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("onConferenceTerminated", map);
    }

    @Override
    public void onConferenceWillJoin(HashMap<String, Object> hashMap) {
        WritableMap map = Arguments.createMap();
        try {
            map.putString("url", hashMap.get("url").toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("onConferenceWillJoin", map);
    }

    @Override
    public void onAudioMutedChanged(HashMap<String, Object> hashMap) {
        WritableMap map = Arguments.createMap();
        try {
            map.putString("muted", hashMap.get("muted").toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("onAudioMutedChanged", map);
    }

    @Override
    public void onParticipantJoined(HashMap<String, Object> hashMap) {
        WritableMap map = Arguments.createMap();
        try {
            map.putString("email", hashMap.get("email").toString());
            map.putString("name", hashMap.get("name").toString());
            map.putString("role", hashMap.get("role").toString());
            map.putString("participantId", hashMap.get("participantId").toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("onParticipantJoined", map);
    }

    @Override
    public void onParticipantLeft(HashMap<String, Object> hashMap) {
        WritableMap map = Arguments.createMap();
        try {
            map.putString("participantId", hashMap.get("participantId").toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("onParticipantLeft", map);
    }

    @Override
    public void onEndpointTextMessageReceived(HashMap<String, Object> hashMap) {
        WritableMap map = Arguments.createMap();
        reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("onEndpointTextMessageReceived", map);
    }

    @Override
    public void onScreenShareToggled(HashMap<String, Object> hashMap) {
        WritableMap map = Arguments.createMap();
        try {
            map.putString("participantId", hashMap.get("participantId").toString());
            map.putString("sharing", hashMap.get("sharing").toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("onScreenShareToggled", map);
    }

    @Override
    public void onParticipantsInfoRetrieved(HashMap<String, Object> hashMap) {
        WritableMap map = Arguments.createMap();
        reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("onParticipantsInfoRetrieved", map);
    }

    @Override
    public void onChatMessageReceived(HashMap<String, Object> hashMap) {
        WritableMap map = Arguments.createMap();
        try {
            map.putString("senderId", hashMap.get("senderId").toString());
            map.putString("message", hashMap.get("message").toString());
            map.putString("isPrivate", hashMap.get("isPrivate").toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("onChatMessageReceived", map);
    }

    @Override
    public void onChatToggled(HashMap<String, Object> hashMap) {
        WritableMap map = Arguments.createMap();
        try {
            map.putString("isOpen", hashMap.get("isOpen").toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("onChatToggled", map);
    }

    @Override
    public void onVideoMutedChanged(HashMap<String, Object> hashMap) {
        WritableMap map = Arguments.createMap();
        try {
            map.putString("muted", hashMap.get("muted").toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("onVideoMutedChanged", map);
    }

    @Override
    public void onReadyToClose(HashMap<String, Object> hashMap) {
        WritableMap map = Arguments.createMap();
        reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("onVideoMutedChanged", map);
    }
}
