package com.castlabs.reactnative;

import android.os.Build;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

import com.castlabs.reactnative.arch_new.NativeNetworkModule;
import com.castlabs.reactnative.arch_new.NativePlayerModule;
import com.castlabs.reactnative.arch_new.NativeSdkModule;
import com.castlabs.reactnative.network.NetworkModule;
import com.castlabs.reactnative.network.RequestCompleter;
import com.castlabs.reactnative.network.ResponseCompleter;
import com.castlabs.reactnative.player.Player;
import com.castlabs.reactnative.player.PlayerEventEmitter;
import com.castlabs.reactnative.player.PlayerModule;
import com.castlabs.reactnative.playerview.PlayerView;
import com.castlabs.reactnative.arch_new.PlayerViewManager;
import com.castlabs.reactnative.sdk.Plugin;
import com.castlabs.reactnative.sdk.SDKModule;
import com.facebook.react.BaseReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.module.model.ReactModuleInfo;
import com.facebook.react.module.model.ReactModuleInfoProvider;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Bundles media views and modules.
 */
@RequiresApi(api = Build.VERSION_CODES.N)
public class PrestoPlayPackage extends BaseReactPackage {
  public static final Map<String, Player> playerInstanceManager = Collections.synchronizedMap(new HashMap<String, Player>());
  public static final Map<String, PlayerView> playerViewInstanceManager = Collections.synchronizedMap(new HashMap<String, PlayerView>());
  public static final List<Plugin> pluginInstanceManager = Collections.synchronizedList(new ArrayList<Plugin>());

  public static final Map<String, RequestCompleter> requestCompleterCache = Collections.synchronizedMap(new HashMap<String, RequestCompleter>());
  public static final Map<String, ResponseCompleter> responseCompleterCache = Collections.synchronizedMap(new HashMap<String, ResponseCompleter>());

  @NonNull
  @Override
  public List<ViewManager> createViewManagers(
      @NonNull ReactApplicationContext context
  ) {
    return new ArrayList<>(List.of(
        new PlayerViewManager(
            context,
            playerInstanceManager,
            playerViewInstanceManager
        )
    ));
  }

  @Nullable
  @Override
  public NativeModule getModule(@NonNull String name, @NonNull ReactApplicationContext reactApplicationContext) {

    if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
      /**
       * Bridgeless (new) architecture
       */
      if (name.equals(NativePlayerModule.NAME)) {
        return new NativePlayerModule(
                reactApplicationContext,
                playerInstanceManager,
                playerViewInstanceManager,
                pluginInstanceManager,
                requestCompleterCache,
                responseCompleterCache);
      } else if (name.equals(NativeSdkModule.NAME)) {
        return new NativeSdkModule(
                pluginInstanceManager,
                reactApplicationContext);
      } else if (name.equals(NativeNetworkModule.NAME)) {
        return new NativeNetworkModule(
                reactApplicationContext,
                requestCompleterCache,
                responseCompleterCache);
      }
    } else {
      /**
       * Bridge (old) architecture
       */
      if (name.equals(PlayerModule.REACT_CLASS)) {

        PlayerEventEmitter eventEmitter = new PlayerEventEmitter((event) -> {
          reactApplicationContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                  .emit("PrestoPlayEvent", event);
        });
        return new PlayerModule(
                reactApplicationContext,
                playerInstanceManager,
                playerViewInstanceManager,
                pluginInstanceManager,
                requestCompleterCache,
                responseCompleterCache,
                eventEmitter);
      } else if (name.equals(NetworkModule.REACT_CLASS)) {
        return new NetworkModule(
                reactApplicationContext,
                requestCompleterCache,
                responseCompleterCache);
      } else if (name.equals(SDKModule.REACT_CLASS)) {
        return new SDKModule(
                pluginInstanceManager,
                reactApplicationContext);
      }
    }
    return null;
  }

  @NonNull
  @Override
  public ReactModuleInfoProvider getReactModuleInfoProvider() {
    return new ReactModuleInfoProvider() {
      @Override
      public Map<String, ReactModuleInfo> getReactModuleInfos() {
        Map<String, ReactModuleInfo> map = new HashMap<>();

        if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
          map.put(NativePlayerModule.NAME, new ReactModuleInfo(
                  NativePlayerModule.NAME,       // name
                  NativePlayerModule.NAME,       // className
                  false, // canOverrideExistingModule
                  false, // needsEagerInit
                  false, // isCXXModule
                  true   // isTurboModule
          ));
          map.put(NativeSdkModule.NAME, new ReactModuleInfo(
                  NativeSdkModule.NAME,       // name
                  NativeSdkModule.NAME,       // className
                  false, // canOverrideExistingModule
                  false, // needsEagerInit
                  false, // isCXXModule
                  true   // isTurboModule
          ));
          map.put(NativeNetworkModule.NAME, new ReactModuleInfo(
                  NativeNetworkModule.NAME,       // name
                  NativeNetworkModule.NAME,       // className
                  false, // canOverrideExistingModule
                  false, // needsEagerInit
                  false, // isCXXModule
                  true   // isTurboModule
          ));
        } else {
          map.put(PlayerModule.REACT_CLASS, new ReactModuleInfo(
                  PlayerModule.REACT_CLASS,       // name
                  PlayerModule.REACT_CLASS,       // className
                  false, // canOverrideExistingModule
                  false, // needsEagerInit
                  false, // isCXXModule
                  false   // isTurboModule
          ));

          map.put(NetworkModule.REACT_CLASS, new ReactModuleInfo(
                  NetworkModule.REACT_CLASS,       // name
                  NetworkModule.REACT_CLASS,       // className
                  false, // canOverrideExistingModule
                  false, // needsEagerInit
                  false, // isCXXModule
                  false   // isTurboModule
          ));

          map.put(SDKModule.REACT_CLASS, new ReactModuleInfo(
                  SDKModule.REACT_CLASS,       // name
                  SDKModule.REACT_CLASS,       // className
                  false, // canOverrideExistingModule
                  false, // needsEagerInit
                  false, // isCXXModule
                  false   // isTurboModule
          ));
        }
        return map;
      }
    };
  }
}
