package com.castlabs.reactnative.sdk;
import android.util.Log;
import androidx.annotation.NonNull;
import com.castlabs.android.PlayerSDK;
import com.castlabs.reactnative.errors.ErrorCode;
import com.castlabs.reactnative.errors.ErrorSeverity;
import com.castlabs.reactnative.errors.PrestoPlayError;
import com.castlabs.reactnative.errors.Rejecter;
import com.castlabs.reactnative.utils.BridgeDeserializer;
import com.facebook.react.bridge.NativeModule;
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.ReadableMap;
import com.facebook.react.bridge.ReadableType;
import com.facebook.react.module.annotations.ReactModule;
import java.util.List;

// Ignore checkstyle

/**
 * The bridge used to interact with SDK.
 */
@SuppressWarnings("checkstyle:AbbreviationAsWordInName")
@ReactModule(name="SDKModule")
public class SDKModule extends ReactContextBaseJavaModule {
  private final List<Plugin> pluginInstanceManager;

  public static final String REACT_CLASS = "SDKModule";

  public SDKModule(
      List<Plugin> pluginInstanceManager,
      ReactApplicationContext applicationContext
  ) {
    super(applicationContext);
    this.pluginInstanceManager = pluginInstanceManager;
  }

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

  /**
   * Initializes the SDK with the given configuration.
   *
   * @param jsonSdkConfiguration The SDK configuration
   * @param companionSdkInfo The companion SDK descriptor
   * @param promise The promise
   */
  @ReactMethod
  public void initialize(ReadableMap jsonSdkConfiguration,
                         ReadableMap companionSdkInfo,
                         Promise promise) {
    if (companionSdkInfo.getString("name") == null)  {
      throw new AssertionError("companionSdkInfo.name cannot be null");
    }
    if (companionSdkInfo.getString("version") == null)  {
      throw new AssertionError("companionSdkInfo.version cannot be null");
    }

    // Get Android SDK configuration
    ReadableMap androidSdkConfig = jsonSdkConfiguration.getMap("androidSdkConfiguration");
    if (androidSdkConfig != null) {
      if (androidSdkConfig.getType("forceSingleDrmSession") == ReadableType.Boolean) {
        PlayerSDK.FORCE_SINGLE_DRM_SESSION = androidSdkConfig.getBoolean("forceSingleDrmSession");
      }
    }

    // Get the license key
    String licenseKey = jsonSdkConfiguration.getString("licenseKey");
    if (licenseKey == null) {
      new Rejecter(promise).reject(
          new PrestoPlayError(
              ErrorSeverity.FATAL,
              ErrorCode.SDK_INVALID_LICENCE
          )
      );
    } else {
      PlayerSDK.ENABLE_ERROR_RESPONSE_BODY = true;
      PlayerSDK.COMPANION_SDK_NAME = companionSdkInfo.getString("name");
      PlayerSDK.COMPANION_SDK_VERSION = companionSdkInfo.getString("version");

      discoverPlugins(jsonSdkConfiguration);

      for (Plugin plugin : pluginInstanceManager) {
        plugin.onSdkWillInitialize();
      }

        int reactLogLevel = jsonSdkConfiguration.getInt("logLevel");
        PlayerSDK.setSdkLogLevel(getAndroidLogLevel(reactLogLevel));
        PlayerSDK.init(getReactApplicationContext(), licenseKey);
        promise.resolve(null);
    }
  }

  private void discoverPlugins(ReadableMap jsonSdkConfiguration) {
    List<String> pluginFactoryModuleNames =
        BridgeDeserializer.toPluginFactoryModuleNames(jsonSdkConfiguration);

    for (String pluginFactoryModuleName : pluginFactoryModuleNames) {
      PluginFactory pluginFactory = (PluginFactory) getNativeModuleByName(pluginFactoryModuleName);
      if (pluginFactory != null) {
        Plugin plugin = pluginFactory.getPlugin();
        pluginInstanceManager.add(plugin);
      } else {
        Log.w("SDKModule", "getNativeModuleByName NULL for: "+pluginFactoryModuleName);
      }
    }
  }

  private NativeModule getNativeModuleByName(String name) {
    ReactApplicationContext reactApplicationContext = this.getReactApplicationContext();

    /* Bridgeless */
    for (NativeModule module : reactApplicationContext.getNativeModules()) {
      if (module.getName().equals(name)) {
        Log.d("SDKModule", "Using bridgeless module for: "+name);
        return module;
      }
    }
    Log.d("SDKModule", "Using legacy module for: "+name);
    /* Legacy */
    return reactApplicationContext.getNativeModule(name);
  }

  private int getAndroidLogLevel(int reactLogLevel) {
    switch (reactLogLevel) {
      case 0: return Log.ASSERT;
      case 1: return Log.ERROR;
      case 2: return Log.WARN;
      case 3: return Log.INFO;
      case 4:
      default: return Log.DEBUG;
    }
  }
}
