package com.webidmetaplugin

import android.content.Intent
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
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.ReadableArray
import com.facebook.react.modules.core.DeviceEventManagerModule
import de.webidsolutions.auto_ident_on_server_product_plugin.AutoIdentOnServerProductPlugin
import de.webidsolutions.eid_on_server_product_plugin.EIdOnServerProductPlugin
import de.webidsolutions.meta_plugin.WebIdMetaPlugin
import de.webidsolutions.mobile_app.sdk.WebIdSdkEnvironment
import de.webidsolutions.pay_on_server_product_plugin.PayOnServerProductPlugin
import de.webidsolutions.plugin_core.IEPluginError
import de.webidsolutions.plugin_core.IProductPluginWebId
import de.webidsolutions.video_ident.plugin.videocall.VideoOptionsConfig
import de.webidsolutions.video_ident_product_plugin.VideoIdentProductPlugin
import java.net.URI

class WebIdMetaPluginModule(
  private val reactContext: ReactApplicationContext
) : ReactContextBaseJavaModule(reactContext) {

  private var metaPlugin: WebIdMetaPlugin? = null

  override fun getName() = "WebIdMetaPlugin"

  private fun sendEvent(eventName: String, data: String) {
    reactContext
      .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
      .emit(eventName, data)
  }

  // ------------------------------------------------
  // CREATE
  // ------------------------------------------------

  @ReactMethod
  fun createMetaPlugin(
    uri: String,
    username: String,
    apiKey: String,
    shaPins: ReadableArray,
    plugins: ReadableArray,
    promise: Promise
  ) {
    try {
      val environment = WebIdSdkEnvironment(
        URI.create(uri),
        *shaPins.toArrayList().map { it.toString() }.toTypedArray()
      )

      val selectedPlugins = ArrayList<de.webidsolutions.plugin_core.IProductPluginWebId>()

      plugins.toArrayList().forEach {
        when (it.toString()) {
          "AutoIdOnServer" -> selectedPlugins.add(AutoIdentOnServerProductPlugin())
          "PayOnServer" -> selectedPlugins.add(PayOnServerProductPlugin())
          "VideoId" -> selectedPlugins.add(VideoIdentProductPlugin(config = VideoOptionsConfig()))
          "EIdOnServer" -> selectedPlugins.add(EIdOnServerProductPlugin())
        }
      }

      metaPlugin = WebIdMetaPlugin(
        environment,
        username,
        apiKey,
        reactApplicationContext,
        selectedPlugins
      )

      promise.resolve("MetaPluginCreated")
    } catch (e: Exception) {
      promise.reject("CREATE_ERROR", e.message)
    }
  }

  // ------------------------------------------------
  // VERIFY
  // ------------------------------------------------

  @ReactMethod
  fun verifyActionId(actionId: String, promise: Promise) {
    try {
      val result = metaPlugin?.verify(actionId)
      promise.resolve(result.toString())
    } catch (e: Exception) {
      promise.reject("VERIFY_ERROR", e.message)
    }
  }

  // ------------------------------------------------
  // START (needs ActivityResultLauncher)
  // ------------------------------------------------

  @ReactMethod
  fun start(promise: Promise) {
    val activity = reactApplicationContext.currentActivity

    if (activity !is FragmentActivity) {
      promise.reject("NO_ACTIVITY", "Current activity is not a FragmentActivity")
      return
    }

    val plugin = metaPlugin
    if (plugin == null) {
      promise.reject("SDK_NOT_INITIALIZED", "MetaPlugin not created. Call createMetaPlugin() first.")
      return
    }

    try {
      val fragment = WebIdResultHostFragment.getOrCreate(
        activity = activity,
        onResult = { resultCode, data ->
          try {
            val result = data?.let {
              IProductPluginWebId.getProductPluginResult<IEPluginError>(it, resultCode)
            }

            if (result?.error == null) {
              sendEvent("WebIdSdkEvent.finishedSuccess", result?.info ?: "")
            } else {
              sendEvent("WebIdSdkEvent.finishedFailed", result.error.toString())
            }
          } catch (e: Exception) {
            sendEvent("WebIdSdkEvent.finishedFailed", e.message ?: "Unknown")
          }
        }
      )

      val customTheme: Int? = null

      plugin.startPlugin(
        activity,
        fragment.launcher,
        customTheme
      )

      promise.resolve("PluginStarted")
    } catch (e: Exception) {
      promise.reject("START_ERROR", e.message)
    }
  }

  // ------------------------------------------------
  // Helper fragment
  // ------------------------------------------------

  class WebIdResultHostFragment : Fragment() {

    private var onResult: ((resultCode: Int, data: Intent?) -> Unit)? = null

    lateinit var launcher: ActivityResultLauncher<Intent>
      private set

    override fun onCreate(savedInstanceState: android.os.Bundle?) {
      super.onCreate(savedInstanceState)

      launcher =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
          onResult?.invoke(result.resultCode, result.data)
        }
    }

    companion object {
      private const val TAG = "WebIdResultHostFragment"

      fun getOrCreate(
        activity: FragmentActivity,
        onResult: (resultCode: Int, data: Intent?) -> Unit
      ): WebIdResultHostFragment {
        val fm = activity.supportFragmentManager

        val existing = fm.findFragmentByTag(TAG) as? WebIdResultHostFragment
        if (existing != null) {
          existing.onResult = onResult
          return existing
        }

        val fragment = WebIdResultHostFragment().apply {
          this.onResult = onResult
        }

        fm.beginTransaction()
          .add(fragment, TAG)
          .commitNowAllowingStateLoss()

        return fragment
      }
    }
  }
}
