// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import { baseUri } from "./base_uri.js";

/**
 * Handles injecting the main Flutter web entrypoint (main.dart.js), and notifying
 * the user when Flutter is ready, through `didCreateEngineInitializer`.
 *
 * @see https://docs.flutter.dev/development/platform-integration/web/initialization
 */
export class FlutterEntrypointLoader {
  /**
   * Creates a FlutterEntrypointLoader.
   */
  constructor() {
    // Watchdog to prevent injecting the main entrypoint multiple times.
    this._scriptLoaded = false;
  }
  /**
   * Injects a TrustedTypesPolicy (or undefined if the feature is not supported).
   * @param {TrustedTypesPolicy | undefined} policy
   */
  setTrustedTypesPolicy(policy) {
    this._ttPolicy = policy;
  }
  /**
   * @deprecated
   * Loads flutter main entrypoint, specified by `entrypointUrl`, and calls a
   * user-specified `onEntrypointLoaded` callback with an EngineInitializer
   * object when it's done.
   *
   * @param {*} options
   * @returns {Promise | undefined} that will eventually resolve with an
   * EngineInitializer, or will be rejected with the error caused by the loader.
   * Returns undefined when an `onEntrypointLoaded` callback is supplied in `options`.
   */
  async loadEntrypoint(options) {
    const { entrypointUrl = `${baseUri}main.dart.js`, onEntrypointLoaded, nonce } =
      options || {};
    return this._loadJSEntrypoint(entrypointUrl, onEntrypointLoaded, nonce);
  }

  /**
   * Loads the entry point for a flutter application.
   * @param {import("./types").ApplicationBuild} build
   *   Information about the specific build that is to be loaded
   * @param {*} deps
   *   External dependencies that may be needed to load the app.
   * @param {import("./types").FlutterConfiguration} config
   *   The application configuration. If no callback is specified, this will be
   *   passed along to engine when initializing it.
   * @param {string} nonce
   *   A nonce to apply to the main application script tag, if necessary.
   * @param {import("./types").OnEntrypointLoadedCallback?} onEntrypointLoaded
   *   An optional callback to invoke when the entrypoint is loaded. If no
   *   callback is supplied, the engine initializer and app runner will be
   *   automatically invoked on load, passing along the supplied flutter
   *   configuration.
   */
  async load(build, deps, config, nonce, onEntrypointLoaded) {
    onEntrypointLoaded ??= (engineInitializer) => {
      engineInitializer.initializeEngine(config).then((appRunner) => appRunner.runApp())
    };
    if (build.compileTarget === "dart2wasm") {
      return this._loadWasmEntrypoint(build, deps, onEntrypointLoaded);
    } else {
      const mainPath = build.mainJsPath ?? "main.dart.js";
      const entrypointUrl = `${baseUri}${mainPath}`;
      return this._loadJSEntrypoint(entrypointUrl, onEntrypointLoaded, nonce);
    }
  }

  /**
   * Resolves the promise created by loadEntrypoint, and calls the `onEntrypointLoaded`
   * function supplied by the user (if needed).
   *
   * Called by Flutter through `_flutter.loader.didCreateEngineInitializer` method,
   * which is bound to the correct instance of the FlutterEntrypointLoader by
   * the FlutterLoader object.
   *
   * @param {Function} engineInitializer @see https://github.com/flutter/engine/blob/main/lib/web_ui/lib/src/engine/js_interop/js_loader.dart#L42
   */
  didCreateEngineInitializer(engineInitializer) {
    if (typeof this._didCreateEngineInitializerResolve === "function") {
      this._didCreateEngineInitializerResolve(engineInitializer);
      // Remove the resolver after the first time, so Flutter Web can hot restart.
      this._didCreateEngineInitializerResolve = null;
      // Make the engine revert to "auto" initialization on hot restart.
      delete _flutter.loader.didCreateEngineInitializer;
    }
    if (typeof this._onEntrypointLoaded === "function") {
      this._onEntrypointLoaded(engineInitializer);
    }
  }
  /**
   * Injects a script tag into the DOM, and configures this loader to be able to
   * handle the "entrypoint loaded" notifications received from Flutter web.
   *
   * @param {string} entrypointUrl the URL of the script that will initialize
   *                 Flutter.
   * @param {Function} onEntrypointLoaded a callback that will be called when
   *                   Flutter web notifies this object that the entrypoint is
   *                   loaded.
   * @returns {Promise | undefined} a Promise that resolves when the entrypoint
   *                                is loaded, or undefined if `onEntrypointLoaded`
   *                                is a function.
   */
  _loadJSEntrypoint(entrypointUrl, onEntrypointLoaded, nonce) {
    const useCallback = typeof onEntrypointLoaded === "function";
    if (!this._scriptLoaded) {
      this._scriptLoaded = true;
      const scriptTag = this._createScriptTag(entrypointUrl, nonce);
      if (useCallback) {
        // Just inject the script tag, and return nothing; Flutter will call
        // `didCreateEngineInitializer` when it's done.
        console.debug("Injecting <script> tag. Using callback.");
        this._onEntrypointLoaded = onEntrypointLoaded;
        document.head.append(scriptTag);
      } else {
        // Inject the script tag and return a promise that will get resolved
        // with the EngineInitializer object from Flutter when it calls
        // `didCreateEngineInitializer` later.
        return new Promise((resolve, reject) => {
          console.debug(
            "Injecting <script> tag. Using Promises. Use the callback approach instead!"
          );
          this._didCreateEngineInitializerResolve = resolve;
          scriptTag.addEventListener("error", reject);
          document.head.append(scriptTag);
        });
      }
    }
  }

  /**
   *
   * @param {import("./types").WasmApplicationBuild} build
   * @param {*} deps
   * @param {import("./types").OnEntrypointLoadedCallback} onEntrypointLoaded
   */
  async _loadWasmEntrypoint(build, deps, onEntrypointLoaded) {
    if (!this._scriptLoaded) {
      this._scriptLoaded = true;

      this._onEntrypointLoaded = onEntrypointLoaded;
      const { mainWasmPath, jsSupportRuntimePath } = build;
      const moduleUri = `${baseUri}${mainWasmPath}`;
      let jsSupportRuntimeUri = `${baseUri}${jsSupportRuntimePath}`;
      if (this._ttPolicy != null) {
        jsSupportRuntimeUri = this._ttPolicy.createScriptURL(jsSupportRuntimeUri);
      }  
      const dartModulePromise = WebAssembly.compileStreaming(fetch(moduleUri));

      const jsSupportRuntime = await import(jsSupportRuntimeUri);

      let imports;
      if (build.renderer === "skwasm") {
        imports = (async () => {
          const skwasmInstance = await deps.skwasm;
          window._flutter_skwasmInstance = skwasmInstance;
          return {
            skwasm: skwasmInstance.wasmExports,
            skwasmWrapper: skwasmInstance,
            ffi: {
              memory: skwasmInstance.wasmMemory,
            },
          };
        })();
      } else {
        imports = {};
      }
      const moduleInstance = await jsSupportRuntime.instantiate(dartModulePromise, imports);
      await jsSupportRuntime.invoke(moduleInstance);
    }
  }

  /**
   * Creates a script tag for the given URL.
   * @param {string} url
   * @returns {HTMLScriptElement}
   */
  _createScriptTag(url, nonce) {
    const scriptTag = document.createElement("script");
    scriptTag.type = "application/javascript";
    if (nonce) {
      scriptTag.nonce = nonce;
    }
    // Apply TrustedTypes validation, if available.
    let trustedUrl = url;
    if (this._ttPolicy != null) {
      trustedUrl = this._ttPolicy.createScriptURL(url);
    }
    scriptTag.src = trustedUrl;
    return scriptTag;
  }
}
