// 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.

// TODO(yjbanov): rename this file to web_only_api.dart.
//                https://github.com/flutter/flutter/issues/100394

// This file contains extra web-only API that non-web engines do not have.
//
// Why have web-only API?
//
// Because all Dart code is compiled (and tree shaken) as a single compilation
// unit it only has one entry-point - the `main()` function of the Flutter
// app. The top-level `main()` is generated by Flutter tool and it needs to
// ask the engine to initialize itself before calling the handwritten `main()`
// function of the app itself. To do that, it needs something to call. The
// mobile engine doesn't provide a function like that because the application
// starts from the Java (Android) or Objective-C (iOS). Any initial
// configuration can be done in Java and the engine's C++ code prior to
// calling Dart's `main()`.

part of ui;

/// Performs one-time initialization of the web environment that supports the
/// Flutter framework.
///
/// This is only available on the Web, as native Flutter configures the
/// environment in the native embedder.
Future<void> webOnlyInitializePlatform() async {
  await engine.initializeEngine();
}

/// Initializes essential bits of the engine before it fully initializes.
/// When [didCreateEngineInitializer] is set, it delegates engine initialization
/// and app startup to the programmer.
/// Else, it immediately triggers the full engine + app bootstrap.
///
/// This method is called by the flutter_tools package, from the entrypoint that
/// it generates around the main method provided by the programmer. See:
/// * https://github.com/flutter/flutter/blob/2bd3e0d914854aa8c12e933f25c5fd8532ae5571/packages/flutter_tools/lib/src/build_system/targets/web.dart#L135-L163
/// * https://github.com/flutter/flutter/blob/61fb2de52c7bdac19b7f2f74eaf3f11237e1e91d/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart#L460-L485
///
/// This function first calls [engine.initializeEngineServices] so the engine
/// can prepare the js-interop layer that is used by web apps (instead of the
/// old `ui.webOnlyFoo` methods/getters).
///
/// It then creates a JsObject that is passed to the [didCreateEngineInitializer]
/// JS callback, to delegate bootstrapping the app to the programmer.
///
/// If said callback is not defined, this assumes that the Flutter Web app is
/// initializing "automatically", as was normal before this feature was
/// introduced. This will immediately run the initEngine and runApp methods
/// (via [engine.AppBootstrap.now]).
///
/// This is the only bit of `dart:ui` that should be directly called by Flutter
/// web apps. Everything else should go through the JS-interop layer created in
/// `engine.warmup`.
///
/// This method should NOT trigger the download of any additional resources
/// (except when the app is in "autoStart" mode).
Future<void> webOnlyWarmupEngine({
  Function? registerPlugins,
  Function? runApp,
}) async {
  // Create the object that knows how to bootstrap an app from JS and Dart.
  final engine.AppBootstrap bootstrap = engine.AppBootstrap(
    initEngine: () async {
      await engine.initializeEngineServices();
    }, runApp: () async {
      if (registerPlugins != null) {
        registerPlugins();
      }
      await engine.initializeEngineUi();
      if (runApp != null) {
        runApp();
      }
    },
  );

  // Should the app "autoStart"?
  bool autoStart = true;
  try {
    autoStart = engine.didCreateEngineInitializer == null;
  } catch (e) {
    // Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'loader')
    autoStart = true;
  }
  if (autoStart) {
    // The user does not want control of the app, bootstrap immediately.
    print('Flutter Web Bootstrap: Auto');
    await bootstrap.autoStart();
  } else {
    // Yield control of the bootstrap procedure to the user.
    print('Flutter Web Bootstrap: Programmatic');
    engine.didCreateEngineInitializer!(bootstrap.prepareEngineInitializer());
  }
}

/// Emulates the `flutter test` environment.
///
/// When set to true, the engine will emulate a specific screen size, and always
/// use the "Ahem" font to reduce test flakiness and dependence on the test
/// environment.
bool get debugEmulateFlutterTesterEnvironment =>
    _debugEmulateFlutterTesterEnvironment;
set debugEmulateFlutterTesterEnvironment(bool value) {
  _debugEmulateFlutterTesterEnvironment = value;
  if (_debugEmulateFlutterTesterEnvironment) {
    const Size logicalSize = Size(800.0, 600.0);
    engine.window.webOnlyDebugPhysicalSizeOverride =
        logicalSize * window.devicePixelRatio;
  }
}

bool _debugEmulateFlutterTesterEnvironment = false;

/// Provides the asset manager.
// TODO(yjbanov): this function should not return a private type. Instead, we
//                should create a public interface for the returned value that's
//                implemented by the engine.
//                https://github.com/flutter/flutter/issues/100394
engine.AssetManager get webOnlyAssetManager => engine.assetManager;

/// Sets the handler that forwards platform messages to web plugins.
///
/// This function exists because unlike mobile, on the web plugins are also
/// implemented using Dart code, and that code needs a way to receive messages.
void webOnlySetPluginHandler(Future<void> Function(String, ByteData?, PlatformMessageResponseCallback?) handler) {
  engine.pluginMessageCallHandler = handler;
}

/// A function which takes a unique `id` and creates an HTML element.
typedef PlatformViewFactory = html.Element Function(int viewId);

/// A registry for factories that create platform views.
class PlatformViewRegistry {
  /// Register [viewTypeId] as being creating by the given [factory].
  bool registerViewFactory(String viewTypeId, PlatformViewFactory viewFactory,
      {bool isVisible = true}) {
    // TODO(web): Deprecate this once there's another way of calling `registerFactory` (js interop?)
    return engine.platformViewManager
        .registerFactory(viewTypeId, viewFactory, isVisible: isVisible);
  }
}

/// The platform view registry for this app.
final PlatformViewRegistry platformViewRegistry = PlatformViewRegistry();
