/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.react.devsupport.interfaces

import android.app.Activity
import android.util.Pair
import android.view.View
import com.facebook.react.bridge.JSExceptionHandler
import com.facebook.react.bridge.ReactContext
import com.facebook.react.bridge.ReadableArray
import com.facebook.react.common.SurfaceDelegate
import com.facebook.react.modules.debug.interfaces.DeveloperSettings
import java.io.File

/**
 * Interface for accessing and interacting with development features. In dev mode, use the
 * implementation [BridgeDevSupportManager]. In production mode, use the dummy implementation
 * [ReleaseDevSupportManager].
 */
public interface DevSupportManager : JSExceptionHandler {

  public val devSettings: DeveloperSettings?
  public val redBoxHandler: RedBoxHandler?
  public val sourceMapUrl: String?
  public val sourceUrl: String?
  public val jSBundleURLForRemoteDebugging: String?
  public val downloadedJSBundleFile: String?
  public val lastErrorTitle: String?
  public val lastErrorStack: Array<StackFrame>?
  public val lastErrorType: ErrorType?
  public val lastErrorCookie: Int
  public val currentActivity: Activity?

  public var devSupportEnabled: Boolean

  public fun showNewJavaError(message: String?, e: Throwable?)

  public fun addCustomDevOption(optionName: String?, optionHandler: DevOptionHandler?)

  public fun createRootView(appKey: String?): View?

  public fun destroyRootView(rootView: View?)

  public fun showNewJSError(message: String?, details: ReadableArray?, errorCookie: Int)

  public fun updateJSError(message: String?, details: ReadableArray?, errorCookie: Int)

  public fun hideRedboxDialog()

  public fun showDevOptionsDialog()

  public fun startInspector()

  public fun stopInspector()

  public fun onNewReactContextCreated(reactContext: ReactContext)

  public fun onReactInstanceDestroyed(reactContext: ReactContext)

  public fun hasUpToDateJSBundleInCache(): Boolean

  public fun reloadSettings()

  public fun handleReloadJS()

  public fun reloadJSFromServer(bundleURL: String, callback: BundleLoadCallback)

  public fun loadSplitBundleFromServer(bundlePath: String, callback: DevSplitBundleCallback)

  public fun isPackagerRunning(callback: PackagerStatusCallback)

  public fun setHotModuleReplacementEnabled(isHotModuleReplacementEnabled: Boolean)

  public fun setRemoteJSDebugEnabled(isRemoteJSDebugEnabled: Boolean)

  public fun setFpsDebugEnabled(isFpsDebugEnabled: Boolean)

  public fun toggleElementInspector()

  public fun downloadBundleResourceFromUrlSync(resourceURL: String, outputFile: File?): File?

  public fun registerErrorCustomizer(errorCustomizer: ErrorCustomizer?)

  public fun processErrorCustomizers(
      errorInfo: Pair<String, Array<StackFrame>>?
  ): Pair<String, Array<StackFrame>>?

  public fun setPackagerLocationCustomizer(packagerLocationCustomizer: PackagerLocationCustomizer?)

  /**
   * Create the surface delegate that the provided module should use to interact with
   *
   * @param moduleName the module name that helps decide which surface it should interact with
   * @return a [SurfaceDelegate] instance
   */
  public fun createSurfaceDelegate(moduleName: String?): SurfaceDelegate?

  /** Attempt to open the JS debugger on the host machine. */
  public fun openDebugger()

  /** Shows the "paused in debugger" overlay with the given message. */
  public fun showPausedInDebuggerOverlay(
      message: String,
      listener: PausedInDebuggerOverlayCommandListener,
  )

  /** Hides the "paused in debugger" overlay, if currently shown. */
  public fun hidePausedInDebuggerOverlay()

  /** Add an option to send to packager when requesting JS bundle. */
  public fun setAdditionalOptionForPackager(name: String, value: String)

  /**
   * The PackagerLocationCustomizer allows you to have a dynamic packager location that is
   * determined right before loading the packager. Your customizer must call |callback|, as loading
   * will be blocked waiting for it to resolve.
   */
  public fun interface PackagerLocationCustomizer {
    public fun run(callback: Runnable?)
  }

  public interface PausedInDebuggerOverlayCommandListener {
    public fun onResume()
  }
}
